Rain World Modding rainworldmoddingwiki https://rainworldmodding.miraheze.org/wiki/Main_Page MediaWiki 1.40.1 case-sensitive Media Special Talk User User talk Rain World Modding Rain World Modding talk File File talk MediaWiki MediaWiki talk Template Template talk Help Help talk Category Category talk UserWiki UserWiki talk User profile User profile talk Campaign Campaign talk Module Module talk Main Page 0 1 1 2022-08-05T06:31:44Z MediaWiki default 1 Create main page wikitext text/x-wiki __NOTOC__ == Welcome to {{SITENAME}}! == This Main Page was created automatically and it seems it hasn't been replaced yet. === For the bureaucrat(s) of this wiki === Hello, and welcome to your new wiki! Thank you for choosing Miraheze for the hosting of your wiki, we hope you will enjoy our hosting. You can immediately start working on your wiki or whenever you want. Need help? No problem! We will help you with your wiki as needed. To start, try checking out these helpful links: * [[mw:Special:MyLanguage/Help:Contents|MediaWiki guide]] (e.g. navigation, editing, deleting pages, blocking users) * [[meta:Special:MyLanguage/FAQ|Miraheze FAQ]] * [[meta:Special:MyLanguage/Request features|Request settings changes on your wiki]]. (Extensions, Skin and Logo/Favicon changes should be done through [[Special:ManageWiki]] on your wiki, see [[meta:Special:MyLanguage/ManageWiki|ManageWiki]] for more information.) ==== I still don't understand X! ==== Well, that's no problem. Even if something isn't explained in the documentation/FAQ, we are still happy to help you. You can find us here: * [[meta:Special:MyLanguage/Help center|On our own Miraheze wiki]] * On [[phab:|Phabricator]] * On [https://miraheze.org/discord Discord] * On IRC in #miraheze on irc.libera.chat ([irc://irc.libera.chat/%23miraheze direct link]; [https://web.libera.chat/?channel=#miraheze webchat]) === For visitors of this wiki === Hello, the default Main Page of this wiki (this page) has not yet been replaced by the bureaucrat(s) of this wiki. The bureaucrat(s) might still be working on a Main Page, so please check again later! 21236ac3f8d65e5563b6da6b70815ca6bf1e6616 2 1 2022-08-05T10:33:21Z Cashewww 2 Protected "[[Main Page]]" ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite)) [cascading] wikitext text/x-wiki __NOTOC__ == Welcome to {{SITENAME}}! == This Main Page was created automatically and it seems it hasn't been replaced yet. === For the bureaucrat(s) of this wiki === Hello, and welcome to your new wiki! Thank you for choosing Miraheze for the hosting of your wiki, we hope you will enjoy our hosting. You can immediately start working on your wiki or whenever you want. Need help? No problem! We will help you with your wiki as needed. To start, try checking out these helpful links: * [[mw:Special:MyLanguage/Help:Contents|MediaWiki guide]] (e.g. navigation, editing, deleting pages, blocking users) * [[meta:Special:MyLanguage/FAQ|Miraheze FAQ]] * [[meta:Special:MyLanguage/Request features|Request settings changes on your wiki]]. (Extensions, Skin and Logo/Favicon changes should be done through [[Special:ManageWiki]] on your wiki, see [[meta:Special:MyLanguage/ManageWiki|ManageWiki]] for more information.) ==== I still don't understand X! ==== Well, that's no problem. Even if something isn't explained in the documentation/FAQ, we are still happy to help you. You can find us here: * [[meta:Special:MyLanguage/Help center|On our own Miraheze wiki]] * On [[phab:|Phabricator]] * On [https://miraheze.org/discord Discord] * On IRC in #miraheze on irc.libera.chat ([irc://irc.libera.chat/%23miraheze direct link]; [https://web.libera.chat/?channel=#miraheze webchat]) === For visitors of this wiki === Hello, the default Main Page of this wiki (this page) has not yet been replaced by the bureaucrat(s) of this wiki. The bureaucrat(s) might still be working on a Main Page, so please check again later! 21236ac3f8d65e5563b6da6b70815ca6bf1e6616 28 2 2022-08-05T12:12:28Z Cashewww 2 set up main page wikitext text/x-wiki __NOTOC__ [[File:RWModdingTitle.png|800px|frameless|center]] <br> <div id="intro-text" style="text-align: center;"> '''Welcome!''' The Rain World Modding Wiki is a place to share information about modding the video game, ''Rain World''. For more about the game, check out the '''[https://rainworld.miraheze.org/wiki/Rain_World_Wiki Official Rain World Wiki]'''! This wiki is currently in the process of being ported from an old wiki. To get involved, be sure to check out the modding category in the [https://discord.gg/rainworld Rain World Discord]. </div> 50c26b21d1ae2c72e0cdf187ec083f2c169f1848 File:RWModdingTitle.png 6 2 3 2022-08-05T10:52:01Z Cashewww 2 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:Hardhatcat.png 6 3 4 2022-08-05T10:55:46Z Cashewww 2 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 29 4 2022-08-05T12:14:43Z Cashewww 2 Cashewww uploaded a new version of [[File:Hardhatcat.png]] wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:Colorfoot-GUI.png 6 4 5 2022-08-05T10:56:33Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:Colorfoot-GUI0.png 6 5 6 2022-08-05T10:56:58Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:Colorfoot-GUI1.png 6 6 7 2022-08-05T10:57:52Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:Colorfoot-Inkscape.png 6 7 8 2022-08-05T10:58:21Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:GeneratedOI-sample.png 6 8 9 2022-08-05T11:12:59Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:CheckBox.png 6 9 10 2022-08-05T11:14:17Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:ColorPicker.png 6 10 11 2022-08-05T11:21:59Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:ComboBox.png 6 11 12 2022-08-05T11:23:26Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:Dragger.png 6 12 13 2022-08-05T11:25:07Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:HoldButton.png 6 13 14 2022-08-05T11:26:46Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:Image.png 6 14 15 2022-08-05T11:27:23Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:Label.png 6 15 16 2022-08-05T11:27:45Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:RadioButton.png 6 16 17 2022-08-05T11:28:16Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:Rect.png 6 17 18 2022-08-05T11:30:43Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:ScrollBox Box.png 6 18 19 2022-08-05T11:31:16Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:ScrollBox Diagram.png 6 19 20 2022-08-05T11:32:03Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:ScrollBox Tab.png 6 20 21 2022-08-05T11:32:51Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:Slider.png 6 21 22 2022-08-05T11:34:12Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:SliderSubtle.png 6 22 23 2022-08-05T11:34:39Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:LandscapeHI.png 6 23 24 2022-08-05T11:35:23Z Cashewww 2 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 MediaWiki:Common.css 8 24 25 2022-08-05T11:36:20Z Cashewww 2 add rw wiki css css text/css /* CSS placed here will be applied to all skins */ /* custom theme start */ :root { --bg-color: #151015ea; --bg-color-solid: #151015; --txt-color: #eee; --txt-color-dark: #bbb; --url-color: #fab; --url-color-visited: #c8a; --light-border-color: #fff6; --dark-pink: #867; --dark-green: #676; --table-bg-header: #0009; --table-bg: #0005; --edit-url-color: #c9b; --toc-bg-color: #0002; --toc-num-color: #aaa; --leftnavbar-url-color: #fef; --leftnavbar-header-color: #ddd; --header-bg-color: #12101250; --header-tab-bg: linear-gradient(#302530da,#151015da); --header-tab-color: #eee; --embed-bg: #171017b0; --diff-delete: #955; --diff-add: #595; } /* main */ body { background-color: var(--bg-color-solid); background-image: url(https://static.miraheze.org/rainworldmoddingwiki/e/e4/LandscapeHI.png); background-position: center; background-repeat: no-repeat; background-attachment: fixed; background-size: cover; } .mw-body { background-color: var(--bg-color); color: var(--txt-color); border: 1px solid var(--light-border-color); } .mw-body h1, h2, h3, h4, h5, h6 { color: var(--txt-color); } .mw-body a, .mw-parser-output a.external { color: var(--url-color); } .mw-body a:visited, .mw-parser-output a.external:visited { color: var(--url-color-visited) } .mw-body .mw-editsection a { color: var(--edit-url-color); } ul { list-style: disc; } /* table of contents */ .toc { background-color: var(--toc-bg-color); border-radius: 4px; } .tocnumber { color: var(--toc-num-color); } .toctext { color: var(--leftnavbar-url-color) } /* left nav bar */ #mw-panel { background-color: var(--header-bg-color); } #mw-panel a { color: var(--leftnavbar-url-color); font-weight: 600; } #mw-panel span { color: var(--leftnavbar-header-color); } /* header */ #mw-page-base { background: none; } #mw-head { background-color: var(--header-bg-color); } #mw-head .vector-menu-content-list li { background-image: var(--header-tab-bg); } #mw-head a { color: var(--header-tab-color); } #mw-head #p-personal li { background-image: none; } .oo-ui-icon-tray, .oo-ui-icon-bell { background-color: var(--txt-color); } #mw-head #p-personal #pt-userpage a { color: var(--leftnavbar-url-color); } /* thumbnails and embeds */ .thumbinner, .catlinks { background-color: var(--embed-bg) !important; } .catlinks { border-radius: 4px; } .catlinks a { color: var(--leftnavbar-url-color) } .thumbimage { background-color: var(--embed-bg); } /* infoboxes */ .infoboxtable { float: right; padding: 10px; border: 1px solid var(--txt-color); border-radius: 4px; font-size: 90%; margin-left: 1em; margin-bottom: 0.5em; width: 300px } .infoboxtable td { vertical-align: top } .infoboxtable td > div { background-color: var(--embed-bg); font-weight: bold; padding: 0.5px 7px } .infoboxname { background-color: var(--embed-bg); font-size: 110%; font-weight: bold; padding: 0.4em } .infoboxdetails { background-color: var(--embed-bg); padding: 0.15em; } .infoboxname, .infoboxdetails, .infoboxtable .mw-collapsible th{ border-radius: 2px !important; border: 1px solid #767; } .mw-collapsible th { background-color: var(--embed-bg) !important; } /* file history */ #filetoc { background-color: var(--toc-bg-color); border: 1px solid var(--txt-color); border-radius: 2px; } /* footer */ #footer-info li { color: var(--leftnavbar-header-color); } #footer-info a, #footer-places a { color: var(--leftnavbar-url-color); font-weight: 800; } /* image gallery */ li.gallerybox div.thumb { background-color: var(--toc-bg-color); border-radius: 3px; } /* general tables */ .wikitable { background-color: var(--table-bg-color) !important; color: var(--txt-color) !important; } .wikitable th { background-color: var(--table-bg-header) !important; } /* page history comparer */ #pagehistory li.selected { background-color: transparent; outline: none; color: var(--txt-color); border: 1px dashed var(--txt-color); } /* page diff */ .diff-context { background-color: var(--embed-bg); color: var(--txt-color); } .diff-deletedline { border-color: var(--diff-delete); } .diff-deletedline .diffchange { background-color: var(--diff-delete); } .diff-addedline { border-color: var(--diff-add); } .diff-addedline .diffchange { background-color: var(--diff-add); } /* recent changes page */ .oo-ui-tagMultiselectWidget.oo-ui-widget-enabled.oo-ui-tagMultiselectWidget-outlined .oo-ui-tagItemWidget.oo-ui-widget-enabled, .mw-rcfilters-ui-filterTagMultiselectWidget.oo-ui-widget-enabled .oo-ui-tagMultiselectWidget-handle, .oo-ui-tagMultiselectWidget.oo-ui-widget-enabled.oo-ui-tagMultiselectWidget-outlined, .oo-ui-textInputWidget .oo-ui-inputWidget-input, .mw-rcfilters-ui-changesListWrapperWidget .mw-changeslist-legend { background-color: var(--embed-bg); border-radius: 3px; } .mw-rcfilters-ui-filterTagItemWidget .oo-ui-labelElement-label, .oo-ui-buttonElement-button .oo-ui-labelElement-label { color: var(--txt-color-dark); } .mw-rcfilters-ui-filterWrapperWidget-showNewChanges .oo-ui-labelElement-label, .mw-rcfilters-ui-filterTagMultiselectWidget .oo-ui-labelElement-label { color: var(--txt-color); } /* file metadata and licensing */ .toccolours { background-color: var(--embed-bg); } .fileinfo-paramfield { background-color: var(--bg-color-solid) } .licensetpl_wrapper, .licensetpl, .layouttemplate table { background-color: var(--embed-bg) !important; } #mw_metadata th, #mw_metadata td { background-color: var(--embed-bg); } /* uploaded files list */ .mw-datatable th, .mw-datatable td { background-color: var(--embed-bg); } .mw-datatable tr:hover td { background-color: var(--bg-color-solid); } /* search bar */ #searchInput { background-color: var(--embed-bg); border-color: var(--light-border-color); color: var(--txt-color); } /* deleted pages page text box & email text box */ .oo-ui-textInputWidget .oo-ui-inputWidget-input { color: var(--txt-color); } /* help text (extensions manager, etc.) */ .oo-ui-inline-help { color: var(--txt-color-dark) !important; } /* main page page creator */ .createboxInput { background-color: var(--embed-bg); border-color: var(--txt-color-dark); color: var(--txt-color) } .mw-ui-button.mw-ui-progressive, .mw-ui-button.mw-ui-progressive:disabled { background-color: var(--embed-bg); border: 1px solid var(--txt-color-dark); transition: ease-in-out 0.3s; } .mw-ui-button.mw-ui-progressive:hover, .mw-ui-button.mw-ui-progressive:disabled:hover { background-color: var(--embed-bg); border: 1px solid var(--url-color); } .mw-body-content blockquote { border-left: 2px solid #eaecf040; } /* userprofile extension support */ #profile-image img { background-color: transparent; border-radius: 4px; } .no-info-container, .profile-info-container, .profile-on { background-color: var(--embed-bg); border: 1px solid var(--txt-color); border-radius: 4px; color: var(--txt-color); } .profile-info-container { margin-bottom: 20px; } .profile-info-container div { padding: 10px 20px; color: var(--txt-color); } .profile-info-container div b { color: var(--txt-color-dark); font-size: 0.9em; } #profile-toggle-button, .profile-tab-on, .profile-tab { background-color: var(--embed-bg); border: 1px solid var(--txt-color-dark); border-radius: 3px; } .profile-tab-on { background-color: var(--dark-pink); } .profile-on { background-color: var(--dark-green); color: white; padding: 5px; } .profile-update-title, .profile-update-unit-left { color: var(--txt-color); } .eye-container { opacity: 0.8; } .eye-container .title { color: black; } .eye-container .menu .item, .eye-container .menu .item:hover { color: black; } .tux-editor-header { color: #fff; font-size: 14px; } .group-warning { background: #371425; padding: 5px; margin: 5px 0; } .tux-breadcrumb { color: #fff; font-size: 14pt; line-height: 1.25em; } .tux-breadcrumb__item--aggregate { cursor: pointer; color: #FEF; } .ext-translate-language-selector-label { color: #fff; } .ext-translate-language-selector .uls { color: #FEF; cursor: pointer; min-height: 1px; position: relative; } .toctogglelabel { cursor: pointer; color: #fff; } .jquery-tablesorter th.headerSort { background-image: url(https://static.miraheze.org/rainworldwiki/c/c3/RW_sort_both.svg); background-repeat: no-repeat; background-position: right; padding-right: 21px; background-size: 21px; } .jquery-tablesorter th.headerSortUp { background-image: url(https://static.miraheze.org/rainworldwiki/1/11/RW_sort_up.svg); background-repeat: no-repeat; background-position: right; padding-right: 21px; background-size: 21px; } .jquery-tablesorter th.headerSortDown { background-image: url(https://static.miraheze.org/rainworldwiki/9/94/RW_sort_down.svg); background-repeat: no-repeat; background-position: right; padding-right: 21px; background-size: 21px; } .updatedmarker { background-color: #474747; } .warningbox { background-color: #513c4900; border-color: #ffeafc; } .messagebox, .errorbox, .warningbox, .successbox { color: #ffeafd; } .cnotice { background-color: var(--bg-color-solid); } .cnotice-message p { color: var(--txt-color); } #cnotice-toggle-box a img { filter: invert(100%); } form#editcount table { background-color: #0000 !important; } /* languages footer */ .mw-pt-languages, .mw-pt-languages-label { background-color: var(--bg-color-solid); border-radius: 4px; } /* advanced search box */ .mw-search-profile-tabs { background-color: #f8f9fa00; } #mw-searchoptions { background-color: #f8f9fa00; } /* visual edit mode imageboxes */ figure[typeof~="mw:Image/Thumb"], figure[typeof~="mw:Video/Thumb"], figure[typeof~="mw:Audio/Thumb"], figure[typeof~="mw:Image/Frame"], figure[typeof~="mw:Video/Frame"], figure[typeof~="mw:Audio/Frame"] { background-color: var(--embed-bg); } figure[typeof~="mw:Image/Thumb"] > figcaption, figure[typeof~="mw:Video/Thumb"] > figcaption, figure[typeof~="mw:Audio/Thumb"] > figcaption, figure[typeof~="mw:Image/Frame"] > figcaption, figure[typeof~="mw:Video/Frame"] > figcaption, figure[typeof~="mw:Audio/Frame"] > figcaption { background-color: var(--embed-bg); } /* visual edit mode popup box */ .oo-ui-popupWidget-popup { background-color: #241a24; } .mw-rcfilters-ui-filterTagItemWidget .oo-ui-labelElement-label, .oo-ui-buttonElement-button .oo-ui-labelElement-label { color: #000; } /* wiki extension manager */ #managewiki .managewiki-submit-formfields { background: #130e13; } .oo-ui-tabSelectWidget-framed { background-color: #150E15; } .successbox { background-color: #391f39; border-color: #C8CCD1; } /* multimedia viewer */ .mw-mmv-post-image { color: #eee; background-color: #221520; } .mw-ui-button.mw-ui-progressive:not(:disabled) { background-color: #0000; color: #000 !important; border-color: #eee; } .mw-mmv-stripe-button.mw-mmv-description-page-button, .mw-mmv-stripe-button.mw-mmv-description-page-button:active, .mw-mmv-stripe-button.mw-mmv-description-page-button:visited { color: #fff; } .mw-mmv-image.error { background-color: #241a22; } .mw-mmv-image-metadata { border-top: 1px solid #eee; background-color: #170d17; } .mw-mmv-image-links a:visited, .mw-mmv-about-links a:visited, .mw-mmv-image-metadata a:visited { color: #c8a; } .mw-mmv-image-links a, .mw-mmv-about-links a, .mw-mmv-image-metadata a { color: #fab; } /* inline icon placer */ pre, code, .mw-code { background-color: #171017c4; color: #eee; border: 1px solid #eee; } /* mediawiki common css */ .mw-content-ltr.mw-highlight-lines pre, .mw-content-ltr.content .mw-highlight-lines pre { padding-left: 3.5em; box-shadow: inset 2.75em 0 0 #4a2c3f59; } .mw-highlight .linenos { color: #eee; } /* text colour */ .mw-highlight .nc { color: #5A9AFF; } .mw-highlight .c { color: #3dcaca; } .mw-highlight .nv { color: #6C69FF; } .mw-highlight .nf { color: #3C49FF; } .mw-highlight .mh { color: #fff; } .mw-highlight .kc { color: #10b710; font-weight: bold; } .mw-highlight .nd { color: #E10BFF; } .mw-highlight .kt { color: #FF347E; } .mw-highlight .nn { color: #5A9AFF; } /* wiki userpage */ #profile-top { border: none; } .user-section-heading { border: none; line-height: 0px; margin: 0 0 20px 0; } #profile-right { float: none; } #user-page-left { width: 100%; float: right; padding-top: 20px; } #user-page-right { float: right; width: 100%; padding-top: 20px; } #p-personal { background: linear-gradient(to left, #15101560, #15101500); padding-right: 5px; } #mw-panel { background: linear-gradient(to right, #15101550, #15101500); height: 100%; } /* links */ a.new { color: #dd3333 !important; } a[href^="/wiki/User:"], a[href^="/wiki/User:"]:visited { color: #9b59b6; font-style: italic; } /* js breadcrumbs */ .jsbc-breadcrumbs { background-color: #0000; border-color: #eee; } /* hiding ip */ a.mw-anonuserlink bdi { visibility: hidden; font-size: 0; letter-spacing: -0px; } a.mw-anonuserlink bdi:after { content: "Unregistered user"; visibility: visible; font-size: 14px; font-weight: bold; color: white; } /* upload file error */ .messagebox, .errorbox, .warningbox, .successbox { color: #fff; } .errorbox { background-color: #fd2e2e70; border-color: #f75252; } /* discord banners */ .discord-banner { width: 320px; height: 76px; background-image: url("https://discordapp.com/api/guilds/291184728944410624/embed.png?style=banner2"); } .discord-shield { width: 119px; height: 20px; background-image: url("https://discordapp.com/api/guilds/291184728944410624/embed.png?style=shield"); } /* cookies banner */ .mw-cookiewarning-container { background-color: rgb(34, 20, 29); } /* video embeds (youtube, etc.) */ .embedvideo-consent { background-color: #000; } .embedvideo-consent__overlay { color: #eee; } .embedvideowrap { border: var(--txt-color-dark) 1px solid; } /* toolbar notifs popup */ .oo-ui-popupWidget-popup { background-color: #EAECF0; } .oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button { background-color: #EAECF0; } /* page editor */ #wpTextbox1 { background-color: var(--bg-color); color: var(--txt-color); } .editOptions { background-color: var(--bg-color-solid); color: var(--txt-color-dark); } .editOptions .oo-ui-labelElement-label { color: var(--txt-color); } /* fundraising notice */ .cnotice { background: #FCFCFC00; border: 1px solid #eee; } .cnotice-message p { color: #eee; } /* sitewide notice */ #siteNotice td { background-color: var(--embed-bg) !important; border: var(--txt-color-dark) 1px solid !important; } /* frb fundraising notice */ .frb { display: none; background-color: #fff0 !important; } .frb-greeting { color: #eee !important; } .frb-translateme { float: right; font-size: 60%; color: #eee !important; margin-top: -20px !important; } .mw-ui-button { background-color: #0000; border: 1px solid #eee; border-radius: 7px; } .frb-message-icon { height: 3em !important; width: 0em !important; } .frb-message-inner { background-color: #FFF0 !important; border-left: 2px solid #eee !important; border-radius: 7px !important; } .mh-notice--warning { border-left-color: #8c8c8c; background: #fff; } /* custom theme end */ 8491420afeb5abeb915a62865884f20acda60eba File:regcast-sporecat.png 6 25 26 2022-08-05T11:41:04Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:BOI-main.png 6 26 27 2022-08-05T11:44:53Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:cameraAngle2-2.png 6 27 30 2022-08-05T13:16:40Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=Example 2 of custom camera angle setting, rendered result}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} The files were published under GPL v3 license 7fe3a7dee42ba8aa1e20f436e8bb0a9da6dcc3fb File:cameraAngle4-1.png 6 28 31 2022-08-05T13:16:41Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=Example 4 of custom camera angle setting, camera editor view}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} The files were published under GPL v3 license 60338350bd42cd274b4917db70d3f241103e6a07 File:cameraAngle3-2.png 6 29 32 2022-08-05T13:16:43Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=Example 3 of custom camera angle setting, rendered result}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} The files were published under GPL v3 license efe098329c63f5ba597851902137bc8912185374 File:triggerTab.png 6 30 33 2022-08-05T13:16:46Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=Example of triggers tab in devtools}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} The files were published under GPL v3 license a89654f3545104fe2b01d089c55b7e9f5a6749fd File:soundTab.png 6 31 34 2022-08-05T13:37:27Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:DataboxSkyIsland Tut1.png 6 32 35 2022-08-05T13:39:52Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:Databox Tut 2.gif 6 33 36 2022-08-05T13:52:21Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:rfg-5.png 6 34 37 2022-08-05T13:53:21Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=region guide frame}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} GPL v3 a3df3861433a0fb11d464720107f1a097a907149 File:rfg-4.png 6 35 38 2022-08-05T13:53:21Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=region guide frame}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} GPL v3 a3df3861433a0fb11d464720107f1a097a907149 File:rfg-1.png 6 36 39 2022-08-05T13:53:21Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=region guide frame}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} GPL v3 a3df3861433a0fb11d464720107f1a097a907149 File:rfg-7.png 6 37 40 2022-08-05T13:53:26Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=region guide frame}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} GPL v3 a3df3861433a0fb11d464720107f1a097a907149 File:rfg-8.png 6 38 41 2022-08-05T13:53:26Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=region guide frame}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} GPL v3 a3df3861433a0fb11d464720107f1a097a907149 File:rfg-6.png 6 39 42 2022-08-05T13:53:26Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=region guide frame}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} GPL v3 a3df3861433a0fb11d464720107f1a097a907149 File:rfg-9.png 6 40 43 2022-08-05T13:53:29Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=region guide frame}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} GPL v3 a3df3861433a0fb11d464720107f1a097a907149 File:rfg-10.png 6 41 44 2022-08-05T13:53:30Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=region guide frame}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} GPL v3 a3df3861433a0fb11d464720107f1a097a907149 File:rfg-11.png 6 42 45 2022-08-05T13:53:32Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=region guide frame}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} GPL v3 a3df3861433a0fb11d464720107f1a097a907149 File:rfg-12.png 6 43 46 2022-08-05T13:53:38Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=region guide frame}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} GPL v3 a3df3861433a0fb11d464720107f1a097a907149 File:rfg-14.png 6 44 47 2022-08-05T13:53:47Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=region guide frame}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} GPL v3 a3df3861433a0fb11d464720107f1a097a907149 File:rfg-2.png 6 45 48 2022-08-05T13:53:49Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=region guide frame}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} GPL v3 a3df3861433a0fb11d464720107f1a097a907149 File:Custom ShelterA.png 6 46 49 2022-08-05T13:53:51Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:rfg-13.png 6 47 50 2022-08-05T13:53:52Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=region guide frame}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} GPL v3 a3df3861433a0fb11d464720107f1a097a907149 File:rfg-3.png 6 48 51 2022-08-05T13:53:57Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=region guide frame}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} GPL v3 a3df3861433a0fb11d464720107f1a097a907149 File:Custom ShelterB.png 6 49 52 2022-08-05T13:54:23Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:Walltutorial1.png 6 50 53 2022-08-05T13:54:51Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:Walltutorial2.png 6 51 54 2022-08-05T13:55:22Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:regionFormat.png 6 52 55 2022-08-05T13:56:59Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:regionFormatConnection.png 6 53 56 2022-08-05T13:57:50Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:mapConnections.png 6 54 57 2022-08-05T13:58:29Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=Room connections in map view in devtools}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} GPL v3 96b455877086ed15aadf64199983758c5021994f File:mapTab.png 6 55 58 2022-08-05T13:58:29Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=Map tab in devtools}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} GPL v3 08356f0dc9b84040d617c2e888ce4f5a260d2eeb File:mapRender.png 6 56 59 2022-08-05T13:58:29Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=Rendered devtools map}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} GPL v3 b3d1e128694a1c124d27834f35e9235025a20d85 File:mapCanon.png 6 57 60 2022-08-05T13:58:42Z Thalber 3 Uploaded a work by https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors from https://rain-world-modding.github.io/ with UploadWizard wikitext text/x-wiki =={{int:filedesc}}== {{Information |description={{en|1=Canon map view in devrools}} |date=2022-06-17 |source=https://rain-world-modding.github.io/ |author=https://github.com/Rain-World-Modding/Rain-World-Modding.github.io/graphs/contributors |permission= |other versions= }} =={{int:license-header}}== {{subst:Custom license marker added by UW}} GPL v3 23c54ecae8c681313d1adc01d8e01f3660e1a3ff File:editorFront.png 6 58 61 2022-08-05T13:59:00Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:geoEditor.png 6 59 62 2022-08-05T14:01:07Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:geoShortcuts1.gif 6 60 63 2022-08-05T14:02:21Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:geoShortcuts2.png 6 61 64 2022-08-05T14:03:07Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:geoShortcuts3.png 6 62 65 2022-08-05T14:03:49Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:geoLayers.gif 6 63 66 2022-08-05T14:04:23Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:tileEditor.png 6 64 67 2022-08-05T14:05:13Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:tileMaterials.png 6 65 68 2022-08-05T14:05:33Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:effectEditor.png 6 66 69 2022-08-05T14:06:51Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:effectGallery.png 6 67 70 2022-08-05T14:07:57Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:propEditor.png 6 68 71 2022-08-05T14:09:21Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:cameraEditor.png 6 69 72 2022-08-05T14:10:48Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:cameraCorner.gif 6 70 73 2022-08-05T14:12:14Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:cameraAngleDefault.png 6 71 74 2022-08-05T14:12:40Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:cameraAngle1-1.png 6 72 75 2022-08-05T14:13:26Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:cameraAngle2-1.png 6 73 76 2022-08-05T14:15:59Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 Category:Code Mods 14 74 77 2022-08-05T14:16:24Z Cashewww 2 Created page with "Code mods are incredibly versatile. They allow for fixing bugs in the vanilla game, adding quality of life (QoL) features, and all sorts of brand new features including new creatures and gamemodes. Code mods are sometimes included in Region Packs, either as supplimentary features or dependencies of those features." wikitext text/x-wiki Code mods are incredibly versatile. They allow for fixing bugs in the vanilla game, adding quality of life (QoL) features, and all sorts of brand new features including new creatures and gamemodes. Code mods are sometimes included in Region Packs, either as supplimentary features or dependencies of those features. de14b28b0aa6946dedbb65ddec3c34ffb66cf4dd File:cameraAngle3-1.png 6 75 78 2022-08-05T14:16:56Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:cameraAngle4-2.png 6 76 79 2022-08-05T14:19:47Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:lightEditor.png 6 77 80 2022-08-05T14:20:45Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:paletteExplanationFinal.png 6 78 81 2022-08-05T14:21:49Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:railballs.png 6 79 82 2022-08-05T14:22:22Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:bfTilesGuide.png 6 80 83 2022-08-05T14:24:14Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:Square-Stone.png 6 81 84 2022-08-05T14:25:47Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:Basic-Collisions.png 6 82 85 2022-08-05T14:26:20Z SpineEater69 5 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 Rain World Modding:Copyrights 4 83 86 2022-08-05T14:30:10Z Cashewww 2 Created page with "Rain World content and materials are the intellectual property of their respective owners. Content that you make available on Rain World Modding Wiki is licensed under Miraheze's terms of service. Do not make content available on Rain World Modding Wiki where you do not have the necessary rights to grant this license. All textual and graphical content on Rain World Modding Wiki that we may lawfully license is licensed to you under the Creative Commons Attribution-Sha..." wikitext text/x-wiki Rain World content and materials are the intellectual property of their respective owners. Content that you make available on Rain World Modding Wiki is licensed under Miraheze's terms of service. Do not make content available on Rain World Modding Wiki where you do not have the necessary rights to grant this license. All textual and graphical content on Rain World Modding Wiki that we may lawfully license is licensed to you under the Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) unless otherwise noted. 15281a5477fa628ceb0c8710d80b74d9b9fe62a5 Dev Tools 0 84 87 2022-08-05T14:49:33Z Thalber 3 Created page with "== Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game...." wikitext text/x-wiki == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ Caption text |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |- | N+Jump || [menus only] Allows you to reposition the layers in the background image with the mouse. |- | B || [menus only] Saves the new positions of the layers to file. |} ==== Menu controls ==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+ Main devtools controls |- ! '''Key''' !! '''Function''' |- | N+Jump || Allows you to reposition the layers in the background image with the mouse. |- | B || Saves the new positions of the layers to file. |} ==== Cutscene controls ==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+ Cutscene controls |- ! '''Key''' !! '''Function''' |- | M || Activate/Deactivate cutscene editing mode. |- | Left Click || Select and drag keyframes around. |- | J || Add a new keyframe. |- | K || Remove a keyframe. |- | O || Change depth of selected keyframe. |- | L || Offset all keyframes. |- | I || Test playback of cutscene. |} </div> === Main Interface Tabs === Once opening the main dev tools interface with H, the interface is broken up into five different tabs. Each of these tabs are extensive enough to warrant their own pages: * [[Room Settings Tab]] * [[Objects Tab]] * [[Sound Tab]] * [[Map Tab]] * [[Triggers Tab]] [[Category:Devtools]] 52349ad24223e3886ec011941c8e1980e8860d60 89 87 2022-08-05T14:59:46Z Thalber 3 Thalber moved page [[Dev tools]] to [[Dev Tools]] without leaving a redirect: capit wikitext text/x-wiki == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ Caption text |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |- | N+Jump || [menus only] Allows you to reposition the layers in the background image with the mouse. |- | B || [menus only] Saves the new positions of the layers to file. |} ==== Menu controls ==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+ Main devtools controls |- ! '''Key''' !! '''Function''' |- | N+Jump || Allows you to reposition the layers in the background image with the mouse. |- | B || Saves the new positions of the layers to file. |} ==== Cutscene controls ==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+ Cutscene controls |- ! '''Key''' !! '''Function''' |- | M || Activate/Deactivate cutscene editing mode. |- | Left Click || Select and drag keyframes around. |- | J || Add a new keyframe. |- | K || Remove a keyframe. |- | O || Change depth of selected keyframe. |- | L || Offset all keyframes. |- | I || Test playback of cutscene. |} </div> === Main Interface Tabs === Once opening the main dev tools interface with H, the interface is broken up into five different tabs. Each of these tabs are extensive enough to warrant their own pages: * [[Room Settings Tab]] * [[Objects Tab]] * [[Sound Tab]] * [[Map Tab]] * [[Triggers Tab]] [[Category:Devtools]] 52349ad24223e3886ec011941c8e1980e8860d60 Category:Dev Tools 14 85 88 2022-08-05T14:51:46Z Thalber 3 Created page with "Pages desccribing function of in-game devools." wikitext text/x-wiki Pages desccribing function of in-game devools. e30fd404154b480d556931d3af8fafd14bd124d8 Level Editor 0 86 90 2022-08-05T15:00:59Z Dakras 6 Created page with "{{Cleanup}} == The Official Level Editor == (main page image goes here) The Rain World level editor is a powerful tool that allows for the creation of new rooms for the game. It is the same editor the developers used to make all of the rooms for the base game. It takes specially formatted spritesheets and a number of programmed effects and outputs png files that the engine interprets in 3D (as well as an accompanying text file which contains collision and gameplay in..." wikitext text/x-wiki {{Cleanup}} == The Official Level Editor == (main page image goes here) The Rain World level editor is a powerful tool that allows for the creation of new rooms for the game. It is the same editor the developers used to make all of the rooms for the base game. It takes specially formatted spritesheets and a number of programmed effects and outputs png files that the engine interprets in 3D (as well as an accompanying text file which contains collision and gameplay info). You can download the level editor from [https://ln.sync.com/dl/db7b0cf70/nebg7d6b-qg7gjua7-gjdi94jn-xuvivhw3/view/default/8384962820004 here.] === Basic Features Overview === Once you've followed the on-screen instructions for either creating or opening a level, you are presented with the dashboard/preview screen. From here, you can switch between the different editors, load or save your level, and export it for use in-game. The preview presented here requires being manually updated whenever changes are made or when you first open a level. Pressing "1" at any point will bring you back to this screen so you can save your level or switch to a different editor. It's often best to start by modifying the dimensions of the room to your liking using the level size button before beginning to edit. You can change this at any time, but because you set the dimensions manually rather than visually, making changes later is more difficult and poses the risk of accidentally deleting a portion of your room if you aren't careful. From the dashboard you can switch to the Geometry Editor (for defining the level geometry and collision), the Tile Editor (for customizing the tiles and assets that make up the geometry created in the geometry editor), the Effects Editor (for adding procedural effects like erosion or slime, as well as things like plants or chains), the Light Editor (for customizing the light and shadow in your room), or the Prop Editor (for adding additional hand placed props and decals like graffiti). === Control Overview === ==== View controls(numpad): ==== Notice, numlock must be turned on for these controls to have any effect. 8,2,4,6 - View movement 1 - Scrolls the view quickly when held, and a view direction is pressed. 3 - Even faster scroll than above. 9 - Allow the view to move outside the boundaries of the level. ==== Menu buttons(Number row): ==== 1 - Main menu 2 - geometry editor 3 - tile editor 4 - camera editor 5 - Light editor 6 - Room size === Geometry Editor: === Full article here Geometry Editor. Arrow keys - Tool selection( if mouse is over main view. If mouse is over the tools, it will move the cursor instead.) Mouse movement - Primary cursor movement E,S,D,F - Secondary cursor movement Mouse left - Primary cursor, use current tool W - Secondary cursor, use current tool Q - Hold, and press the secondary cursor's movement keys to select the secondary cursor's current tool. === Tile Editor: === Full article here Tile Editor. A, D - Changes tile library's category W, S - Scrolls through tiles in current category Mouse left - Place currently selected tile if possible Mouse right - Remove tile under cursor F - Hold to place "material" category tiles in a 3x3 brush instead of 1x1 V - Same as above, but gives a 5x5 brush Tab+X+C - Clears all tiles, Only loading the last save will undo this, use with caution! L - changes current tile layer ( 1 to 3 and then loops back to 1 ) E - Sets the default material of unpainted tiles. Only works in the "material" category F - Forces a tile that requires certain geometry to be placed, without changing any geometry data. G - Forces a tile that requires certain geometry to be placed, and adds the required geometry. Q - Functions as an "Eyedropper" tool, selecting the tile you're hovering over to place. === Effect Editor: === Full article here Effects Editor. Effect library: A, D - Changes effect library's category W, S - Scrolls through effect in current category E - Switches to editing previously applied effects. Space - Adds the selected effect. Applied effects: W, S - Scrolls through effects applied in room N - Switches to adding new effects from the effect library. Space - edit selected effect Effect editing: A, D - Scrolls through options in the effect's menu W, S - Changes the current effect's menu Space - activates selected option in effect menu Mouse left - Paints current effect Mouse right - removes current effect R - Grows cursor F - Shrinks cursor E or N - Switches back to the menus for editing or adding effects respectively. === Camera Editor: === Full article here Camera Editor. N - New camera, spawns held by mouse E - grab a camera if none is held D - Delete held camera P - Place held camera === Light editor: === Full article here Light Editor. W,A,S,D - Scale current light shape Q, E - Rotate current light shape Z - Toggle between drawing and erasing light Mouse left - Paint light Mouse right - Rotate light shape in direction of mouse ( does not paint it.) R, F - Scroll through light shape library J, L - Change angle of light source I, K - Change distance of light source === Prop Editor: === Full article here Prop Editor. A, D - Changes prop library's category W, S - Scrolls through props in current category Mouse left - Place current prop V - Hold and click mouse left to remove highlighted prop Q, E - Rotate prop left and right Space - Hold to speed up rotation Y,G,H,J - stretch prop T - reset prop stretching R - reset stretching, and rotation Y, H - Only on wires/tube props, Increases or decreases prop's physics node count. Less means more taught, more means more loose X - Pause wire/tube physics Tab+X+C - clear all props B - Click mouse left to set the highlighted prop as the currently selected prop L - Change layer Mouse right - Change prop depth. (There are 10 depths per layer, and each layer counts as 10. So props on layer 2, would start at 10, and count to 19, before going back to 10. Changes the order that props are drawn on top of each other with.) Mouse right + Space - Same as above, except going down in depth instead of up. U, I. O, P - Holds a prop by three vertices, and allows you to move the last one with the mouse to stretch it in a freeform manner. ( U stretches top right, I bottom right, O bottom left, and P top left. ) K - resets freeform stretching. N - allows proper properties to be changed. Things like forcing certain graffiti to be drawn instead of a random one. M - Click with mouse left, to change the highlighted prop's properties (does the same as above, except allows you to edit an already placed prop. ) Z - Changes prop color F + Left or right mouse - Changes between prop variants. This only applies to certain props. === Environment Editor: === L - Change water level based on mouse movement F - Toggles between drawing water above the first layer or below it. W - Removes water from the level if there is already water. If there is no water, sets water level to halfway up the level. == Crash Avoidance and Editor Quirks == Due to the editor being extremely user unfriendly, you are likely to run into various crashes without warning. This is a list of various things to avoid doing. === Crashes: === Do not switch to editing applied effects in the Effects Editor when there are none. The switch will be invisible, and attempting to use the space bar to select something from there will crash the Level Editor. Some effects have very specific conditions and cause issues when rendering, Effects include: Thick Roots, and Shadow Plants. these ones can be okayed through until it renders.) Be sure to remove tiles from parts of a room that will be removed if you resize the room to cut those areas out, those tiles are still recorded, and will crash renders instantly. props are the exact same as above Never render with no cameras. It will crash. Always move the prop menu into an actual category when you open it, it keeps the last menu used, and crashes if you select any entry that is not a real prop. (EX: it will have the effects menu, or tile menu.) If you are using the Mirrored tile placer, in the geometry editor. Placing poles, with the other side of the mirrored brush being outside of the room, will crash the editor. === Quirks: === The main menu is a mess when you return from using the Light Editor or the Environment Editor. Just change to any other editor (geometry or tiles, and back to main menu) to clean it. This is not a crash, but will help prevent confusion if you know to expect this. To use the Move and Move Mirror tools in the editor, you must first select them, and then move your mouse outside of the room itself, before it will respond to your inputs. Usually you will only need to put your mouse over the editor, but in larger rooms, this is often an issue, as the room is "behind" the menu, and thus only changes tool selection. The editor still receives inputs if you only tab out using alt-tab. When viewing another window, it's important to always minimize the editor, because there are many things that can go wrong if you're randomly clicking in the editor. (Requires more confirmation) The screen during rendering should usually show the map being rendered, but it may not. In the task manager, The Rain World Editor is under the tab Adobe Projector. Sometimes the reason it is not showing is a second application called "Print driver host for applications". Closing the application seems to fix the issue. The window for the application may be too big to fit on screen, and cannot be fixed since reaching the top bar or right clicking cannot be accessed to move the window. === Demo and Tutorial Videos === Region Developer Kaeporo created a tutorial for creating levels in and out of the level editor: {{#ev:youtube|YQ0DO-fmPCE|||||urlargs=""}} Mod community member Sacretis also put together a demonstration video, this time covering the creation of a room from scratch to visual polish (massively sped up for the sake of time): {{#ev:youtube|sEE3X1izaJA|||||urlargs=""}} 81948a5e318c89c0adbfd58e164200e9c5765baa 91 90 2022-08-05T15:07:16Z Dakras 6 wikitext text/x-wiki {{Cleanup}} == The Official Level Editor == [[File:editorFront.png|thumb]] The Rain World level editor is a powerful tool that allows for the creation of new rooms for the game. It is the same editor the developers used to make all of the rooms for the base game. It takes specially formatted spritesheets and a number of programmed effects and outputs png files that the engine interprets in 3D (as well as an accompanying text file which contains collision and gameplay info). You can download the level editor from [https://ln.sync.com/dl/db7b0cf70/nebg7d6b-qg7gjua7-gjdi94jn-xuvivhw3/view/default/8384962820004 here.] === Basic Features Overview === Once you've followed the on-screen instructions for either creating or opening a level, you are presented with the dashboard/preview screen. From here, you can switch between the different editors, load or save your level, and export it for use in-game. The preview presented here requires being manually updated whenever changes are made or when you first open a level. Pressing "1" at any point will bring you back to this screen so you can save your level or switch to a different editor. It's often best to start by modifying the dimensions of the room to your liking using the level size button before beginning to edit. You can change this at any time, but because you set the dimensions manually rather than visually, making changes later is more difficult and poses the risk of accidentally deleting a portion of your room if you aren't careful. From the dashboard you can switch to the Geometry Editor (for defining the level geometry and collision), the Tile Editor (for customizing the tiles and assets that make up the geometry created in the geometry editor), the Effects Editor (for adding procedural effects like erosion or slime, as well as things like plants or chains), the Light Editor (for customizing the light and shadow in your room), or the Prop Editor (for adding additional hand placed props and decals like graffiti). === Control Overview === ==== View controls(numpad): ==== Notice, numlock must be turned on for these controls to have any effect. 8,2,4,6 - View movement 1 - Scrolls the view quickly when held, and a view direction is pressed. 3 - Even faster scroll than above. 9 - Allow the view to move outside the boundaries of the level. ==== Menu buttons(Number row): ==== 1 - Main menu 2 - geometry editor 3 - tile editor 4 - camera editor 5 - Light editor 6 - Room size === Geometry Editor: === Full article here Geometry Editor. Arrow keys - Tool selection( if mouse is over main view. If mouse is over the tools, it will move the cursor instead.) Mouse movement - Primary cursor movement E,S,D,F - Secondary cursor movement Mouse left - Primary cursor, use current tool W - Secondary cursor, use current tool Q - Hold, and press the secondary cursor's movement keys to select the secondary cursor's current tool. === Tile Editor: === Full article here Tile Editor. A, D - Changes tile library's category W, S - Scrolls through tiles in current category Mouse left - Place currently selected tile if possible Mouse right - Remove tile under cursor F - Hold to place "material" category tiles in a 3x3 brush instead of 1x1 V - Same as above, but gives a 5x5 brush Tab+X+C - Clears all tiles, Only loading the last save will undo this, use with caution! L - changes current tile layer ( 1 to 3 and then loops back to 1 ) E - Sets the default material of unpainted tiles. Only works in the "material" category F - Forces a tile that requires certain geometry to be placed, without changing any geometry data. G - Forces a tile that requires certain geometry to be placed, and adds the required geometry. Q - Functions as an "Eyedropper" tool, selecting the tile you're hovering over to place. === Effect Editor: === Full article here Effects Editor. Effect library: A, D - Changes effect library's category W, S - Scrolls through effect in current category E - Switches to editing previously applied effects. Space - Adds the selected effect. Applied effects: W, S - Scrolls through effects applied in room N - Switches to adding new effects from the effect library. Space - edit selected effect Effect editing: A, D - Scrolls through options in the effect's menu W, S - Changes the current effect's menu Space - activates selected option in effect menu Mouse left - Paints current effect Mouse right - removes current effect R - Grows cursor F - Shrinks cursor E or N - Switches back to the menus for editing or adding effects respectively. === Camera Editor: === Full article here Camera Editor. N - New camera, spawns held by mouse E - grab a camera if none is held D - Delete held camera P - Place held camera === Light editor: === Full article here Light Editor. W,A,S,D - Scale current light shape Q, E - Rotate current light shape Z - Toggle between drawing and erasing light Mouse left - Paint light Mouse right - Rotate light shape in direction of mouse ( does not paint it.) R, F - Scroll through light shape library J, L - Change angle of light source I, K - Change distance of light source === Prop Editor: === Full article here Prop Editor. A, D - Changes prop library's category W, S - Scrolls through props in current category Mouse left - Place current prop V - Hold and click mouse left to remove highlighted prop Q, E - Rotate prop left and right Space - Hold to speed up rotation Y,G,H,J - stretch prop T - reset prop stretching R - reset stretching, and rotation Y, H - Only on wires/tube props, Increases or decreases prop's physics node count. Less means more taught, more means more loose X - Pause wire/tube physics Tab+X+C - clear all props B - Click mouse left to set the highlighted prop as the currently selected prop L - Change layer Mouse right - Change prop depth. (There are 10 depths per layer, and each layer counts as 10. So props on layer 2, would start at 10, and count to 19, before going back to 10. Changes the order that props are drawn on top of each other with.) Mouse right + Space - Same as above, except going down in depth instead of up. U, I. O, P - Holds a prop by three vertices, and allows you to move the last one with the mouse to stretch it in a freeform manner. ( U stretches top right, I bottom right, O bottom left, and P top left. ) K - resets freeform stretching. N - allows proper properties to be changed. Things like forcing certain graffiti to be drawn instead of a random one. M - Click with mouse left, to change the highlighted prop's properties (does the same as above, except allows you to edit an already placed prop. ) Z - Changes prop color F + Left or right mouse - Changes between prop variants. This only applies to certain props. === Environment Editor: === L - Change water level based on mouse movement F - Toggles between drawing water above the first layer or below it. W - Removes water from the level if there is already water. If there is no water, sets water level to halfway up the level. == Crash Avoidance and Editor Quirks == Due to the editor being extremely user unfriendly, you are likely to run into various crashes without warning. This is a list of various things to avoid doing. === Crashes: === Do not switch to editing applied effects in the Effects Editor when there are none. The switch will be invisible, and attempting to use the space bar to select something from there will crash the Level Editor. Some effects have very specific conditions and cause issues when rendering, Effects include: Thick Roots, and Shadow Plants. these ones can be okayed through until it renders.) Be sure to remove tiles from parts of a room that will be removed if you resize the room to cut those areas out, those tiles are still recorded, and will crash renders instantly. props are the exact same as above Never render with no cameras. It will crash. Always move the prop menu into an actual category when you open it, it keeps the last menu used, and crashes if you select any entry that is not a real prop. (EX: it will have the effects menu, or tile menu.) If you are using the Mirrored tile placer, in the geometry editor. Placing poles, with the other side of the mirrored brush being outside of the room, will crash the editor. === Quirks: === The main menu is a mess when you return from using the Light Editor or the Environment Editor. Just change to any other editor (geometry or tiles, and back to main menu) to clean it. This is not a crash, but will help prevent confusion if you know to expect this. To use the Move and Move Mirror tools in the editor, you must first select them, and then move your mouse outside of the room itself, before it will respond to your inputs. Usually you will only need to put your mouse over the editor, but in larger rooms, this is often an issue, as the room is "behind" the menu, and thus only changes tool selection. The editor still receives inputs if you only tab out using alt-tab. When viewing another window, it's important to always minimize the editor, because there are many things that can go wrong if you're randomly clicking in the editor. (Requires more confirmation) The screen during rendering should usually show the map being rendered, but it may not. In the task manager, The Rain World Editor is under the tab Adobe Projector. Sometimes the reason it is not showing is a second application called "Print driver host for applications". Closing the application seems to fix the issue. The window for the application may be too big to fit on screen, and cannot be fixed since reaching the top bar or right clicking cannot be accessed to move the window. === Demo and Tutorial Videos === Region Developer Kaeporo created a tutorial for creating levels in and out of the level editor: {{#ev:youtube|YQ0DO-fmPCE|||||urlargs=""}} Mod community member Sacretis also put together a demonstration video, this time covering the creation of a room from scratch to visual polish (massively sped up for the sake of time): {{#ev:youtube|sEE3X1izaJA|||||urlargs=""}} 708068b467ff909a60947090813f17cf23c0071e Template:Ambox 10 87 92 2022-08-05T15:08:53Z SpineEater69 5 Created page with "<onlyinclude><includeonly><table style="padding: 2px; border-radius: 0.5em; border: 1px solid {{#switch:{{{border|}}} | red = red; | orange = orange; | yellow = yellow; | purple = purple; | blue = blue; | green = green; | gray = gray; | #default = green; }} {{{style|}}}"> <tr> <td>{{{image|[[File:{{{icon|Information.png{{!}}48px}}}|{{#ifeq:{{{format|}}}|tiny|x20px}}|alt=]]}}}</td> <td>{{{type|}}} {{#if:{{{info|}}}|{{#ifeq:{{{format|}..." wikitext text/x-wiki <onlyinclude><includeonly><table style="padding: 2px; border-radius: 0.5em; border: 1px solid {{#switch:{{{border|}}} | red = red; | orange = orange; | yellow = yellow; | purple = purple; | blue = blue; | green = green; | gray = gray; | #default = green; }} {{{style|}}}"> <tr> <td>{{{image|[[File:{{{icon|Information.png{{!}}48px}}}|{{#ifeq:{{{format|}}}|tiny|x20px}}|alt=]]}}}</td> <td>{{{type|}}} {{#if:{{{info|}}}|{{#ifeq:{{{format|}}}|tiny||<div class="amsmalltext"> {{{info}}} </div>}}}}</td></tr></table></includeonly></onlyinclude><noinclude> [[Category:Notice templates]]</noinclude> a22f7d85dd6cc1beb3bb7d97c85c76a8f853b9c8 Template:Cleanup 10 88 93 2022-08-05T15:09:09Z SpineEater69 5 Created page with "<includeonly><div class="nomobile">{{Ambox | image = <p><span style="margin-right:15px>[[File:Hardhatcat.png|middle]]</span> | type = '''This article needs clean-up to meet quality standards.''' | info = Our community is working hard to rehaul this page. In the meantime, feel free to help {{fullurl|{{FULLPAGENAME}}|action=edit{{#if: {{{1|}}} | &section={{{1}}} }}|text=improve}} what's currently written.</p> | border = gray }}</div></includeonly> <noinclude> Usage: <now..." wikitext text/x-wiki <includeonly><div class="nomobile">{{Ambox | image = <p><span style="margin-right:15px>[[File:Hardhatcat.png|middle]]</span> | type = '''This article needs clean-up to meet quality standards.''' | info = Our community is working hard to rehaul this page. In the meantime, feel free to help {{fullurl|{{FULLPAGENAME}}|action=edit{{#if: {{{1|}}} | &section={{{1}}} }}|text=improve}} what's currently written.</p> | border = gray }}</div></includeonly> <noinclude> Usage: <nowiki>{{Cleanup}}</nowiki> {{Cleanup}} </noinclude> 757d8d58667b2d60d4ec91ee152f0ef17bf5efa5 Template:fullurl 10 89 94 2022-08-05T15:10:21Z SpineEater69 5 Created page with "<includeonly>{{#if: {{{nolink|}}} | <nowiki>http://help.gamepedia.com/index.php?title=</nowiki>{{{1}}}{{#if: {{{2|}}} | &{{{2}}} }} |<!-- --><span class="plainlinks">{{#if: {{{text|}}} | [ }}{{fullurl: {{{1}}} | {{{2|}}} }} {{#if: {{{text|}}} | {{{text}}}]}}</span>}}</includeonly><noinclude>{{doc}} [[Category:Formatting templates|{{PAGENAME}}]]</noinclude>" wikitext text/x-wiki <includeonly>{{#if: {{{nolink|}}} | <nowiki>http://help.gamepedia.com/index.php?title=</nowiki>{{{1}}}{{#if: {{{2|}}} | &{{{2}}} }} |<!-- --><span class="plainlinks">{{#if: {{{text|}}} | [ }}{{fullurl: {{{1}}} | {{{2|}}} }} {{#if: {{{text|}}} | {{{text}}}]}}</span>}}</includeonly><noinclude>{{doc}} [[Category:Formatting templates|{{PAGENAME}}]]</noinclude> 46367eacd22a6dce7076a2ab94d525b760c66e2b 95 94 2022-08-05T15:12:38Z SpineEater69 5 wikitext text/x-wiki <includeonly>{{#if: {{{nolink|}}} | <nowiki>http://help.gamepedia.com/index.php?title=</nowiki>{{{1}}}{{#if: {{{2|}}} | &{{{2}}} }} |<!-- --><span class="plainlinks">{{#if: {{{text|}}} | [ }}{{fullurl: {{{1}}} | {{{2|}}} }} {{#if: {{{text|}}} | {{{text}}}]}}</span>}}</includeonly><noinclude>{{fullurl}} [[Category:Formatting templates|{{PAGENAME}}]]</noinclude> 7c0f669fa59d78a3875d9ec842a52c55ced221bb Main Page 0 1 96 28 2022-08-05T15:25:54Z Cashewww 2 wikitext text/x-wiki __NOTOC__ [[File:RWModdingTitle.png|800px|frameless|center]] <br> <div id="intro-text" style="text-align: center;"> '''Welcome!''' The Rain World Modding Wiki is a place to share information about modding the video game, ''Rain World''. For more about the game, check out the '''[https://rainworld.miraheze.org/wiki/Rain_World_Wiki Official Rain World Wiki]'''! This wiki is currently in the process of being ported from an old wiki. To get involved, be sure to check out the modding category in the [https://discord.gg/rainworld Rain World Discord]. </div> == Where to Start... == * [[Installing Mods]] * [[Categories:Code Mods|Code Mods]] * [[Categories:Levels|Levels]] 98663fb1b71d83ed3f9e82adf637243b69dc5256 Template:Navbox 10 90 97 2022-08-05T15:27:30Z SpineEater69 5 Created page with "<!-- Please do not edit without discussion first as this is a VERY complex template. -->{{#switch:{{{border|{{{1|}}}}}}|subgroup|child=</div>|none=|#default=<table class="navbox {{{bodyclass|}}}" cellspacing="0" <!-- -->style="{{{bodystyle|}}};{{{style|}}}"><tr><td style="padding:2px;">}}<!-- --><table cellspacing="0" class="nowraplinks {{#if:{{{title|}}}|{{#switch:{{{state|}}}|plain|off=|<!-- -->#default=mw-collapsible {{#if:{{{state|}}}|{{{state}}}|mw-collapsed}}}..." wikitext text/x-wiki <!-- Please do not edit without discussion first as this is a VERY complex template. -->{{#switch:{{{border|{{{1|}}}}}}|subgroup|child=</div>|none=|#default=<table class="navbox {{{bodyclass|}}}" cellspacing="0" <!-- -->style="{{{bodystyle|}}};{{{style|}}}"><tr><td style="padding:2px;">}}<!-- --><table cellspacing="0" class="nowraplinks {{#if:{{{title|}}}|{{#switch:{{{state|}}}|plain|off=|<!-- -->#default=mw-collapsible {{#if:{{{state|}}}|{{{state}}}|mw-collapsed}}}}}} {{#switch:{{{border|{{{1|}}}}}}|<!-- -->subgroup|child|none=navbox-subgroup" style="width:100%;{{{bodystyle|}}};{{{style|}}}|<!-- -->#default=" style="width:100%;background:transparent;color:inherit}};{{{innerstyle|}}};" data-expandtext="show" data-collapsetext="hide"><!-- ---Title and Navbar--- -->{{#if:{{{title|}}}|<tr>{{#if:{{{titlegroup|}}}|<!-- --><td class="navbox-group" style="{{{basestyle|}}};{{{groupstyle|}}};{{{titlegroupstyle|}}}">{{{titlegroup|}}}</td><!-- --><th style="border-left:2px solid #fdfdfd;width:100%;|<th style="}}{{{basestyle|}}};{{{titlestyle|}}}" <!-- -->colspan={{#expr:2{{#if:{{{imageleft|}}}|+1}}{{#if:{{{image|}}}|+1}}{{#if:{{{titlegroup|}}}|-1}}}} <!-- -->class="navbox-title"><!-- -->{{#if:{{#switch:{{{navbar|}}}|plain|off=1}}<!-- -->{{#if:{{{name|}}}||{{#switch:{{{border|{{{1|}}}}}}|subgroup|child|none=1}}}}|<!-- -->{{#ifeq:{{{navbar|}}}|off|{{#ifeq:{{{state|}}}|plain|<span style="float:right;width:6em;">&nbsp;</span>}}|<!-- -->{{#ifeq:{{{state|}}}|plain||<span style="float:left;width:6em;">&nbsp;</span>}}}}|<!-- --><span style="float:left;width:6em;text-align:left;">{{#if:{{{name|}}}|<!-- -->{{Navbar|{{{name}}}|mini=1|fontstyle={{{basestyle|}}};{{{titlestyle|}}};<!-- -->background:none transparent;border:none;font-size:100%;}}|<!-- --><span class="error" style="white-space:nowrap;">Error: No name provided</span>}}</span><!-- -->{{#ifeq:{{{state|}}}|plain|<span style="float:right;width:6em;">&nbsp;</span>}}}}<!-- --><span class="{{{titleclass|}}}" style="font-size:{{#switch:{{{border|{{{1|}}}}}}|subgroup|child|none=100|#default=110}}%;"><!-- -->{{{title}}}</span></th></tr>}}<!-- ---Above--- -->{{#if:{{{above|}}}|<!-- -->{{#if:{{{title|}}}|<tr style="height:2px;"><td></td></tr>}}<!-- --><tr><td class="navbox-abovebelow" style="{{{basestyle|}}};{{{abovestyle|}}}" <!-- -->colspan="{{#expr:2{{#if:{{{imageleft|}}}|+1}}{{#if:{{{image|}}}|+1}}}}">{{{above}}}</td></tr>}}<!-- ---Body--- ---First group/list and images--- -->{{#if:{{{list1|}}}|{{#if:{{{title|}}}{{{above|}}}|<tr style="height:2px;"><td></td></tr>}}<tr><!-- -->{{#if:{{{imageleft|}}}|<!-- --><td style="width:0%;padding:0px 2px 0px 0px;{{{imageleftstyle|}}}" <!-- -->rowspan={{#expr:1{{#if:{{{list2|}}}|+2}}{{#if:{{{list3|}}}|+2}}{{#if:{{{list4|}}}|+2}}<!-- -->{{#if:{{{list5|}}}|+2}}{{#if:{{{list6|}}}|+2}}{{#if:{{{list7|}}}|+2}}{{#if:{{{list8|}}}|+2}}<!-- -->{{#if:{{{list9|}}}|+2}}{{#if:{{{list10|}}}|+2}}{{#if:{{{list11|}}}|+2}}{{#if:{{{list12|}}}|+2}}<!-- -->{{#if:{{{list13|}}}|+2}}{{#if:{{{list14|}}}|+2}}{{#if:{{{list15|}}}|+2}}{{#if:{{{list16|}}}|+2}}<!-- -->{{#if:{{{list17|}}}|+2}}{{#if:{{{list18|}}}|+2}}{{#if:{{{list19|}}}|+2}}{{#if:{{{list20|}}}|+2}}}}><!-- -->{{{imageleft}}}</td>}}<!-- -->{{#if:{{{group1|}}}|<td class="navbox-group" style="{{{basestyle|}}};{{#if:{{{groupwidth|}}}|width:{{{groupwidth}}};}}{{{groupstyle|}}};{{{group1style|}}}"><!-- -->{{{group1}}}</td><td style="text-align:left;border-left-width:2px;border-left-style:solid;|<td colspan=2 style="}}<!-- -->{{#if:{{{groupwidth|}}}||width:100%;}}padding:0px;{{{liststyle|}}};{{{oddstyle|}}};{{{list1style|}}}" <!-- -->class="navbox-list navbox-{{#ifeq:{{{evenodd|}}}|swap|even|{{{evenodd|odd}}}}}"><!-- --><div style="padding:{{{list1padding|{{{listpadding|0em 0.25em}}}}}}"> {{{list1}}}</div></td><!-- -->{{#if:{{{image|}}}|<!-- --><td style="width:0%;padding:0px 0px 0px 2px;{{{imagestyle|}}}" <!-- -->rowspan={{#expr:1{{#if:{{{list2|}}}|+2}}{{#if:{{{list3|}}}|+2}}{{#if:{{{list4|}}}|+2}}<!-- -->{{#if:{{{list5|}}}|+2}}{{#if:{{{list6|}}}|+2}}{{#if:{{{list7|}}}|+2}}{{#if:{{{list8|}}}|+2}}<!-- -->{{#if:{{{list9|}}}|+2}}{{#if:{{{list10|}}}|+2}}{{#if:{{{list11|}}}|+2}}{{#if:{{{list12|}}}|+2}}<!-- -->{{#if:{{{list13|}}}|+2}}{{#if:{{{list14|}}}|+2}}{{#if:{{{list15|}}}|+2}}{{#if:{{{list16|}}}|+2}}<!-- -->{{#if:{{{list17|}}}|+2}}{{#if:{{{list18|}}}|+2}}{{#if:{{{list19|}}}|+2}}{{#if:{{{list20|}}}|+2}}}}><!-- -->{{{image}}}</td>}}<!-- --></tr>}}<!-- ---Remaining groups/lists--- -->{{#if:{{{list2|}}}|<!-- -->{{#if:{{{title|}}}{{{above|}}}{{{list1|}}}|<tr style="height:2px"><td></td></tr>}}<tr><!-- -->{{#if:{{{group2|}}}|<td class="navbox-group" style="{{{basestyle|}}};{{#if:{{{groupwidth|}}}|width:{{{groupwidth}}};}}{{{groupstyle|}}};{{{group2style|}}}"><!-- -->{{{group2}}}</td><td style="text-align:left;border-left-width:2px;border-left-style:solid;|<td colspan=2 style="}}<!-- -->{{#if:{{{groupwidth|}}}||width:100%;}}padding:0px;{{{liststyle|}}};{{{evenstyle|}}};{{{list2style|}}}" <!-- -->class="navbox-list navbox-{{#ifeq:{{{evenodd|}}}|swap|odd|{{{evenodd|even}}}}}"><!-- --><div style="padding:{{{listpadding|0em 0.25em}}}"> {{{list2}}}</div></td></tr>}}<!-- -->{{#if:{{{list3|}}}|<!-- -->{{#if:{{{title|}}}{{{above|}}}{{{list1|}}}{{{list2|}}}|<tr style="height:2px"><td></td></tr>}}<tr><!-- -->{{#if:{{{group3|}}}|<td class="navbox-group" style="{{{basestyle|}}};{{#if:{{{groupwidth|}}}|width:{{{groupwidth}}};}}{{{groupstyle|}}};{{{group3style|}}}"><!-- -->{{{group3}}}</td><td style="text-align:left;border-left-width:2px;border-left-style:solid;|<td colspan=2 style="}}<!-- -->{{#if:{{{groupwidth|}}}||width:100%;}}padding:0px;{{{liststyle|}}};{{{oddstyle|}}};{{{list3style|}}}" <!-- -->class="navbox-list navbox-{{#ifeq:{{{evenodd|}}}|swap|even|{{{evenodd|odd}}}}}"><!-- --><div style="padding:{{{listpadding|0em 0.25em}}}"> {{{list3}}}</div></td></tr>}}<!-- -->{{#if:{{{list4|}}}|<!-- --><tr style="height:2px"><td></td></tr><tr><!-- -->{{#if:{{{group4|}}}|<td class="navbox-group" style="{{{basestyle|}}};{{#if:{{{groupwidth|}}}|width:{{{groupwidth}}};}}{{{groupstyle|}}};{{{group4style|}}}"><!-- -->{{{group4}}}</td><td style="text-align:left;border-left-width:2px;border-left-style:solid;|<td colspan=2 style="}}<!-- -->{{#if:{{{groupwidth|}}}||width:100%;}}padding:0px;{{{liststyle|}}};{{{evenstyle|}}};{{{list4style|}}}" <!-- -->class="navbox-list navbox-{{#ifeq:{{{evenodd|}}}|swap|odd|{{{evenodd|even}}}}}"><!-- --><div style="padding:{{{listpadding|0em 0.25em}}}"> {{{list4}}}</div></td></tr>}}<!-- -->{{#if:{{{list5|}}}|<!-- --><tr style="height:2px"><td></td></tr><tr><!-- -->{{#if:{{{group5|}}}|<td class="navbox-group" style="{{{basestyle|}}};{{#if:{{{groupwidth|}}}|width:{{{groupwidth}}};}}{{{groupstyle|}}};{{{group5style|}}}"><!-- -->{{{group5}}}</td><td style="text-align:left;border-left-width:2px;border-left-style:solid;|<td colspan=2 style="}}<!-- -->{{#if:{{{groupwidth|}}}||width:100%;}}padding:0px;{{{liststyle|}}};{{{oddstyle|}}};{{{list5style|}}}" <!-- -->class="navbox-list navbox-{{#ifeq:{{{evenodd|}}}|swap|even|{{{evenodd|odd}}}}}"><!-- --><div style="padding:{{{listpadding|0em 0.25em}}}"> {{{list5}}}</div></td></tr>}}<!-- -->{{#if:{{{list6|}}}|<!-- --><tr style="height:2px"><td></td></tr><tr><!-- -->{{#if:{{{group6|}}}|<td class="navbox-group" style="{{{basestyle|}}};{{#if:{{{groupwidth|}}}|width:{{{groupwidth}}};}}{{{groupstyle|}}};{{{group6style|}}}"><!-- -->{{{group6}}}</td><td style="text-align:left;border-left-width:2px;border-left-style:solid;|<td colspan=2 style="}}<!-- -->{{#if:{{{groupwidth|}}}||width:100%;}}padding:0px;{{{liststyle|}}};{{{evenstyle|}}};{{{list6style|}}}" <!-- -->class="navbox-list navbox-{{#ifeq:{{{evenodd|}}}|swap|odd|{{{evenodd|even}}}}}"><!-- --><div style="padding:{{{listpadding|0em 0.25em}}}"> {{{list6}}}</div></td></tr>}}<!-- -->{{#if:{{{list7|}}}|<!-- --><tr style="height:2px"><td></td></tr><tr><!-- -->{{#if:{{{group7|}}}|<td class="navbox-group" style="{{{basestyle|}}};{{#if:{{{groupwidth|}}}|width:{{{groupwidth}}};}}{{{groupstyle|}}};{{{group7style|}}}"><!-- -->{{{group7}}}</td><td style="text-align:left;border-left-width:2px;border-left-style:solid;|<td colspan=2 style="}}<!-- -->{{#if:{{{groupwidth|}}}||width:100%;}}padding:0px;{{{liststyle|}}};{{{oddstyle|}}};{{{list7style|}}}" <!-- -->class="navbox-list navbox-{{#ifeq:{{{evenodd|}}}|swap|even|{{{evenodd|odd}}}}}"><!-- --><div style="padding:{{{listpadding|0em 0.25em}}}"> {{{list7}}}</div></td></tr>}}<!-- -->{{#if:{{{list8|}}}|<!-- --><tr style="height:2px"><td></td></tr><tr><!-- -->{{#if:{{{group8|}}}|<td class="navbox-group" style="{{{basestyle|}}};{{#if:{{{groupwidth|}}}|width:{{{groupwidth}}};}}{{{groupstyle|}}};{{{group8style|}}}"><!-- -->{{{group8}}}</td><td style="text-align:left;border-left-width:2px;border-left-style:solid;|<td colspan=2 style="}}<!-- -->{{#if:{{{groupwidth|}}}||width:100%;}}padding:0px;{{{liststyle|}}};{{{evenstyle|}}};{{{list8style|}}}" <!-- -->class="navbox-list navbox-{{#ifeq:{{{evenodd|}}}|swap|odd|{{{evenodd|even}}}}}"><!-- --><div style="padding:{{{listpadding|0em 0.25em}}}"> {{{list8}}}</div></td></tr>}}<!-- -->{{#if:{{{list9|}}}|<!-- --><tr style="height:2px"><td></td></tr><tr><!-- -->{{#if:{{{group9|}}}|<td class="navbox-group" style="{{{basestyle|}}};{{#if:{{{groupwidth|}}}|width:{{{groupwidth}}};}}{{{groupstyle|}}};{{{group9style|}}}"><!-- -->{{{group9}}}</td><td style="text-align:left;border-left-width:2px;border-left-style:solid;|<td colspan=2 style="}}<!-- -->{{#if:{{{groupwidth|}}}||width:100%;}}padding:0px;{{{liststyle|}}};{{{oddstyle|}}};{{{list9style|}}}" <!-- -->class="navbox-list navbox-{{#ifeq:{{{evenodd|}}}|swap|even|{{{evenodd|odd}}}}}"><!-- --><div style="padding:{{{listpadding|0em 0.25em}}}"> {{{list9}}}</div></td></tr>}}<!-- -->{{#if:{{{list10|}}}|<!-- --><tr style="height:2px"><td></td></tr><tr><!-- -->{{#if:{{{group10|}}}|<td class="navbox-group" style="{{{basestyle|}}};{{#if:{{{groupwidth|}}}|width:{{{groupwidth}}};}}{{{groupstyle|}}};{{{group10style|}}}"><!-- -->{{{group10}}}</td><td style="text-align:left;border-left-width:2px;border-left-style:solid;|<td colspan=2 style="}}<!-- -->{{#if:{{{groupwidth|}}}||width:100%;}}padding:0px;{{{liststyle|}}};{{{evenstyle|}}};{{{list10style|}}}" <!-- -->class="navbox-list navbox-{{#ifeq:{{{evenodd|}}}|swap|odd|{{{evenodd|even}}}}}"><!-- --><div style="padding:{{{listpadding|0em 0.25em}}}"> {{{list10}}}</div></td></tr>}}<!-- -->{{#if:{{{list11|}}}|<!-- --><tr style="height:2px"><td></td></tr><tr><!-- -->{{#if:{{{group11|}}}|<td class="navbox-group" style="{{{basestyle|}}};{{#if:{{{groupwidth|}}}|width:{{{groupwidth}}};}}{{{groupstyle|}}};{{{group11style|}}}"><!-- -->{{{group11}}}</td><td style="text-align:left;border-left-width:2px;border-left-style:solid;|<td colspan=2 style="}}<!-- -->{{#if:{{{groupwidth|}}}||width:100%;}}padding:0px;{{{liststyle|}}};{{{oddstyle|}}};{{{list11style|}}}" <!-- -->class="navbox-list navbox-{{#ifeq:{{{evenodd|}}}|swap|even|{{{evenodd|odd}}}}}"><!-- --><div style="padding:{{{listpadding|0em 0.25em}}}"> {{{list11}}}</div></td></tr>}}<!-- -->{{#if:{{{list12|}}}|<!-- --><tr style="height:2px"><td></td></tr><tr><!-- -->{{#if:{{{group12|}}}|<td class="navbox-group" style="{{{basestyle|}}};{{#if:{{{groupwidth|}}}|width:{{{groupwidth}}};}}{{{groupstyle|}}};{{{group12style|}}}"><!-- -->{{{group12}}}</td><td style="text-align:left;border-left-width:2px;border-left-style:solid;|<td colspan=2 style="}}<!-- -->{{#if:{{{groupwidth|}}}||width:100%;}}padding:0px;{{{liststyle|}}};{{{evenstyle|}}};{{{list12style|}}}" <!-- -->class="navbox-list navbox-{{#ifeq:{{{evenodd|}}}|swap|odd|{{{evenodd|even}}}}}"><!-- --><div style="padding:{{{listpadding|0em 0.25em}}}"> {{{list12}}}</div></td></tr>}}<!-- -->{{#if:{{{list13|}}}|<!-- --><tr style="height:2px"><td></td></tr><tr><!-- -->{{#if:{{{group13|}}}|<td class="navbox-group" style="{{{basestyle|}}};{{#if:{{{groupwidth|}}}|width:{{{groupwidth}}};}}{{{groupstyle|}}};{{{group13style|}}}"><!-- -->{{{group13}}}</td><td style="text-align:left;border-left-width:2px;border-left-style:solid;|<td colspan=2 style="}}<!-- -->{{#if:{{{groupwidth|}}}||width:100%;}}padding:0px;{{{liststyle|}}};{{{oddstyle|}}};{{{list13style|}}}" <!-- -->class="navbox-list navbox-{{#ifeq:{{{evenodd|}}}|swap|even|{{{evenodd|odd}}}}}"><!-- --><div style="padding:{{{listpadding|0em 0.25em}}}"> {{{list13}}}</div></td></tr>}}<!-- -->{{#if:{{{list14|}}}|<!-- --><tr style="height:2px"><td></td></tr><tr><!-- -->{{#if:{{{group14|}}}|<td class="navbox-group" style="{{{basestyle|}}};{{#if:{{{groupwidth|}}}|width:{{{groupwidth}}};}}{{{groupstyle|}}};{{{group14style|}}}"><!-- -->{{{group14}}}</td><td style="text-align:left;border-left-width:2px;border-left-style:solid;|<td colspan=2 style="}}<!-- -->{{#if:{{{groupwidth|}}}||width:100%;}}padding:0px;{{{liststyle|}}};{{{evenstyle|}}};{{{list14style|}}}" <!-- -->class="navbox-list navbox-{{#ifeq:{{{evenodd|}}}|swap|odd|{{{evenodd|even}}}}}"><!-- --><div style="padding:{{{listpadding|0em 0.25em}}}"> {{{list14}}}</div></td></tr>}}<!-- -->{{#if:{{{list15|}}}|<!-- --><tr style="height:2px"><td></td></tr><tr><!-- -->{{#if:{{{group15|}}}|<td class="navbox-group" style="{{{basestyle|}}};{{#if:{{{groupwidth|}}}|width:{{{groupwidth}}};}}{{{groupstyle|}}};{{{group15style|}}}"><!-- -->{{{group15}}}</td><td style="text-align:left;border-left-width:2px;border-left-style:solid;|<td colspan=2 style="}}<!-- -->{{#if:{{{groupwidth|}}}||width:100%;}}padding:0px;{{{liststyle|}}};{{{oddstyle|}}};{{{list15style|}}}" <!-- -->class="navbox-list navbox-{{#ifeq:{{{evenodd|}}}|swap|even|{{{evenodd|odd}}}}}"><!-- --><div style="padding:{{{listpadding|0em 0.25em}}}"> {{{list15}}}</div></td></tr>}}<!-- -->{{#if:{{{list16|}}}|<!-- --><tr style="height:2px"><td></td></tr><tr><!-- -->{{#if:{{{group16|}}}|<td class="navbox-group" style="{{{basestyle|}}};{{#if:{{{groupwidth|}}}|width:{{{groupwidth}}};}}{{{groupstyle|}}};{{{group16style|}}}"><!-- -->{{{group16}}}</td><td style="text-align:left;border-left-width:2px;border-left-style:solid;|<td colspan=2 style="}}<!-- -->{{#if:{{{groupwidth|}}}||width:100%;}}padding:0px;{{{liststyle|}}};{{{evenstyle|}}};{{{list16style|}}}" <!-- -->class="navbox-list navbox-{{#ifeq:{{{evenodd|}}}|swap|odd|{{{evenodd|even}}}}}"><!-- --><div style="padding:{{{listpadding|0em 0.25em}}}"> {{{list16}}}</div></td></tr>}}<!-- -->{{#if:{{{list17|}}}|<!-- --><tr style="height:2px"><td></td></tr><tr><!-- -->{{#if:{{{group17|}}}|<td class="navbox-group" style="{{{basestyle|}}};{{#if:{{{groupwidth|}}}|width:{{{groupwidth}}};}}{{{groupstyle|}}};{{{group17style|}}}"><!-- -->{{{group17}}}</td><td style="text-align:left;border-left-width:2px;border-left-style:solid;|<td colspan=2 style="}}<!-- -->{{#if:{{{groupwidth|}}}||width:100%;}}padding:0px;{{{liststyle|}}};{{{oddstyle|}}};{{{list17style|}}}" <!-- -->class="navbox-list navbox-{{#ifeq:{{{evenodd|}}}|swap|even|{{{evenodd|odd}}}}}"><!-- --><div style="padding:{{{listpadding|0em 0.25em}}}"> {{{list17}}}</div></td></tr>}}<!-- -->{{#if:{{{list18|}}}|<!-- --><tr style="height:2px"><td></td></tr><tr><!-- -->{{#if:{{{group18|}}}|<td class="navbox-group" style="{{{basestyle|}}};{{#if:{{{groupwidth|}}}|width:{{{groupwidth}}};}}{{{groupstyle|}}};{{{group18style|}}}"><!-- -->{{{group18}}}</td><td style="text-align:left;border-left-width:2px;border-left-style:solid;|<td colspan=2 style="}}<!-- -->{{#if:{{{groupwidth|}}}||width:100%;}}padding:0px;{{{liststyle|}}};{{{evenstyle|}}};{{{list18style|}}}" <!-- -->class="navbox-list navbox-{{#ifeq:{{{evenodd|}}}|swap|odd|{{{evenodd|even}}}}}"><!-- --><div style="padding:{{{listpadding|0em 0.25em}}}"> {{{list18}}}</div></td></tr>}}<!-- -->{{#if:{{{list19|}}}|<!-- --><tr style="height:2px"><td></td></tr><tr><!-- -->{{#if:{{{group19|}}}|<td class="navbox-group" style="{{{basestyle|}}};{{#if:{{{groupwidth|}}}|width:{{{groupwidth}}};}}{{{groupstyle|}}};{{{group19style|}}}"><!-- -->{{{group19}}}</td><td style="text-align:left;border-left-width:2px;border-left-style:solid;|<td colspan=2 style="}}<!-- -->{{#if:{{{groupwidth|}}}||width:100%;}}padding:0px;{{{liststyle|}}};{{{oddstyle|}}};{{{list19style|}}}" <!-- -->class="navbox-list navbox-{{#ifeq:{{{evenodd|}}}|swap|even|{{{evenodd|odd}}}}}"><!-- --><div style="padding:{{{listpadding|0em 0.25em}}}"> {{{list19}}}</div></td></tr>}}<!-- -->{{#if:{{{list20|}}}|<!-- --><tr style="height:2px"><td></td></tr><tr><!-- -->{{#if:{{{group20|}}}|<td class="navbox-group" style="{{{basestyle|}}};{{#if:{{{groupwidth|}}}|width:{{{groupwidth}}};}}{{{groupstyle|}}};{{{group20style|}}}"><!-- -->{{{group20}}}</td><td style="text-align:left;border-left-width:2px;border-left-style:solid;|<td colspan=2 style="}}<!-- -->{{#if:{{{groupwidth|}}}||width:100%;}}padding:0px;{{{liststyle|}}};{{{evenstyle|}}};{{{list20style|}}}" <!-- -->class="navbox-list navbox-{{#ifeq:{{{evenodd|}}}|swap|odd|{{{evenodd|even}}}}}"><!-- --><div style="padding:{{{listpadding|0em 0.25em}}}"> {{{list20}}}</div></td></tr>}}<!-- ---Below--- -->{{#if:{{{below|}}}|<!-- -->{{#if:{{{title|}}}{{{above|}}}{{{list1|}}}{{{list2|}}}{{{list3|}}}|<tr style="height:2px;"><td></td></tr>}}<!-- --><tr><td class="navbox-abovebelow" style="{{{basestyle|}}};{{{belowstyle|}}}" <!-- -->colspan="{{#expr:2{{#if:{{{imageleft|}}}|+1}}{{#if:{{{image|}}}|+1}}}}">{{{below}}}</td></tr>}}<!-- --></table>{{#switch:{{{border|{{{1|}}}}}}|subgroup|child=<div>|none=|#default=</td></tr></table>}} <noinclude>{{doc}}[[Category:Navigation templates]]</noinclude> a079487dc65f0aa8d764c5fc56cee4cfd4cc5dff Template:GlobalNavbox 10 91 98 2022-08-05T15:29:51Z SpineEater69 5 Created page with "<includeonly><div style="clear: both"></div> ----{{Navbox |name = GlobalNavbox |style = background:#000000; width:100% |state = uncollapsed |lliststyle = background:#0a070a |title = '''Wiki Navigation''' |group1 = '''Mechanics''' |list1 = [[Achievements]] {{*}} [[Behavior]] {{*}} [[Controls]] ([[Combat]] {{*}} [[Pole Movement]] {{*}} [[Rolls]] {{*}} [[Slides]] {{*}} [[Swimming]] {{*}} [[Tunnel Movement]]) {{*}} [[Creatures]] ([[Lineage System]]) {{*}} [[Difficulties]] {{..." wikitext text/x-wiki <includeonly><div style="clear: both"></div> ----{{Navbox |name = GlobalNavbox |style = background:#000000; width:100% |state = uncollapsed |lliststyle = background:#0a070a |title = '''Wiki Navigation''' |group1 = '''Mechanics''' |list1 = [[Achievements]] {{*}} [[Behavior]] {{*}} [[Controls]] ([[Combat]] {{*}} [[Pole Movement]] {{*}} [[Rolls]] {{*}} [[Slides]] {{*}} [[Swimming]] {{*}} [[Tunnel Movement]]) {{*}} [[Creatures]] ([[Lineage System]]) {{*}} [[Difficulties]] {{*}} [[Health]] {{*}} [[Hibernation]] ([[Food]]) {{*}} [[Karma]] ([[Karma Gate]]) {{*}} [[Objects]] {{*}} [[Regions]] ---- |group2 = '''Misc''' |list2 = [[Developers]] {{*}} [[Music]] {{*}} [[Rain World]] }}</includeonly><noinclude> {{GlobalNavbox}} (currently completely copy/pasted from rw main wiki, links will be swapped out eventually) </noinclude> 4d0c16987df452b109aa58f14637b0a5b058083d Template:Navbar 10 92 99 2022-08-05T15:30:28Z SpineEater69 5 Created page with "<includeonly><span class="noprint plainlinks navbar" style="{{{style|}}}"><!-- -->{{#if:{{{mini|}}}{{{plain|}}}|<!--nothing-->|<!--else: --><span style="{{{fontstyle|}}}">{{{text|This box:}}} </span>}}<!-- -->{{#if:{{{brackets|}}}|<span style="{{{fontstyle|}}}">&#91;</span>}}<!-- --><span style="white-space:nowrap;word-spacing:-.12em;"><!-- -->[[{{transclude|{{{1}}}}}|<span style="{{{fontstyle|}}}" title="View this template"><!-- -->{{#if:{{{mini|}}}|v|view}}</span>]]..." wikitext text/x-wiki <includeonly><span class="noprint plainlinks navbar" style="{{{style|}}}"><!-- -->{{#if:{{{mini|}}}{{{plain|}}}|<!--nothing-->|<!--else: --><span style="{{{fontstyle|}}}">{{{text|This box:}}} </span>}}<!-- -->{{#if:{{{brackets|}}}|<span style="{{{fontstyle|}}}">&#91;</span>}}<!-- --><span style="white-space:nowrap;word-spacing:-.12em;"><!-- -->[[{{transclude|{{{1}}}}}|<span style="{{{fontstyle|}}}" title="View this template"><!-- -->{{#if:{{{mini|}}}|v|view}}</span>]]<!-- --><span style="{{{fontstyle|}}}">&#32;<b>&middot;</b>&#32;</span><!-- -->[[{{TALKPAGENAME:{{transclude|{{{1}}}}}}}|<span style="{{{fontstyle|}}}" title="Discuss this template"><!-- -->{{#if:{{{mini|}}}|d|talk}}</span>]]<!-- -->{{#if:{{{noedit|}}}|<!--nothing-->|<!--else: --><span style="{{{fontstyle|}}}">&#32;<b>&middot;</b>&#32;</span><!-- -->[{{fullurl:{{transclude|{{{1}}}}}|action=edit}} <span style="{{{fontstyle|}}}" title="Edit this template"><!-- -->{{#if:{{{mini|}}}|e|edit}}</span>]}}<!-- --></span><!-- -->{{#if:{{{brackets|}}}|<span style="{{{fontstyle|}}}">&#93;</span>}}<!-- --></span></includeonly><noinclude>[[Category:Navigation templates]]</noinclude> fbbb9922078d8207cb8fdc31c395750d8d81ee49 Template:transclude 10 93 100 2022-08-05T15:31:25Z SpineEater69 5 Created page with "{{#switch: {{NAMESPACE: {{{1}}} }} |#default = {{FULLPAGENAME: {{{1}}} }} <!-- eg "User:Foo" --> |{{ns:0}} = {{#ifeq: {{NAMESPACE: {{{1}}} }} | {{NAMESPACE: Template{{{1}}} }} | Template:{{{1}}} <!-- no leading colon, eg "Foo" --> | {{PAGENAME: {{{1}}} }} <!-- leading colon, eg ":Foo", so we want the article --> }} }}<noinclude>[[Category:Templates]] </noinclude>" wikitext text/x-wiki {{#switch: {{NAMESPACE: {{{1}}} }} |#default = {{FULLPAGENAME: {{{1}}} }} <!-- eg "User:Foo" --> |{{ns:0}} = {{#ifeq: {{NAMESPACE: {{{1}}} }} | {{NAMESPACE: Template{{{1}}} }} | Template:{{{1}}} <!-- no leading colon, eg "Foo" --> | {{PAGENAME: {{{1}}} }} <!-- leading colon, eg ":Foo", so we want the article --> }} }}<noinclude>[[Category:Templates]] </noinclude> caf327b539e0d23bc4a657528088fb403830bb7f Level Editor 0 86 101 91 2022-08-05T17:00:44Z Thalber 3 Changed keybinds to tables wikitext text/x-wiki {{Cleanup}} == The Official Level Editor == [[File:editorFront.png|thumb]] The Rain World level editor is a powerful tool that allows for the creation of new rooms for the game. It is the same editor the developers used to make all of the rooms for the base game. It takes specially formatted spritesheets and a number of programmed effects and outputs png files that the engine interprets in 3D (as well as an accompanying text file which contains collision and gameplay info). You can download the level editor from [https://ln.sync.com/dl/db7b0cf70/nebg7d6b-qg7gjua7-gjdi94jn-xuvivhw3/view/default/8384962820004 here.] === Basic Features Overview === Once you've followed the on-screen instructions for either creating or opening a level, you are presented with the dashboard/preview screen. From here, you can switch between the different editors, load or save your level, and export it for use in-game. The preview presented here requires being manually updated whenever changes are made or when you first open a level. Pressing "1" at any point will bring you back to this screen so you can save your level or switch to a different editor. It's often best to start by modifying the dimensions of the room to your liking using the level size button before beginning to edit. You can change this at any time, but because you set the dimensions manually rather than visually, making changes later is more difficult and poses the risk of accidentally deleting a portion of your room if you aren't careful. From the dashboard you can switch to the Geometry Editor (for defining the level geometry and collision), the Tile Editor (for customizing the tiles and assets that make up the geometry created in the geometry editor), the Effects Editor (for adding procedural effects like erosion or slime, as well as things like plants or chains), the Light Editor (for customizing the light and shadow in your room), or the Prop Editor (for adding additional hand placed props and decals like graffiti). === Control Overview === ==== View controls (numpad): ==== Notice, numlock must be turned on for these controls to have any effect. {| class="wikitable" |+ |- ! Key(s) !! Function |- | 8,2,4,6 || Moves view |- | 1 (hold) || Increases view scroll speed. |- | 3 (hold) || Increases view scroll speed even more. |- | 9 (hold) || Allow the view to move outside the boundaries of the level. |} ==== Menu keybinds (Number row): ==== These act as hotkeys to quickly switch between different editor views. {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | 1 || Main menu |- | 2 || Geometry |- | 3 || Tiles |- | 4 || Cameras |- | 5 || Light |- | 6 || Room size |} === Geometry Editor: === Full article here [[Geometry Editor]]. {| class="wikitable" |+ Geometry editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | Arrow keys || Primary cursor scroll through toolbox. If mouse over the toolbox, mouse moves cursor instead. |- | Mouse || Primary cursor movement. |- | LMB || Primary cursor use current tool. |- | Q (hold) || Secondary cursor scroll through toolbox. |- | E,S,D,F || Secondary cursor movement. |- | W || Secondary cursor use current tool. |} === Tile Editor: === Full article here [[Tile Editor]]. {| class="wikitable" |+ Tile editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Select tile category |- | W,S || Select tile in current category |- | LMB || Place tile under cursor |- | RMB || Erase tile under cursor |- | F (hold) || Use a 3x3 brush for materials |- | V (hold) || Use a 5x5 brush for materials |- | Tab+x+c || Clears all tiles |- | L || Change active layer (1, 2, 3, loop back to 1) |- | E || Sets default material of the room to the currently selected material |- | F (hold) || Enables force placing selected tile (ignoring geometry, erasing colliding tiles) |- | G (hold) || Enables force placing selected tile (forcing appropriate geometry for the tile, erasing colliding tiles) |- | Q || "Eyedropper" (selects tile/material hovered over) |} === Effect Editor: === Full article here [[Effects Editor]]. {| class="wikitable" |+ Effect library keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Select effect category |- | W,S || Select effect in current category |- | E || Switches to editing applied effects |- | Space || Adds selected effect to the stack |} {| class="wikitable" |+ Applied effect keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,S || Scroll through the effect stack |- | N || Switch to effect library |- | Space || Edit selected effect in the stack |} Effect editing: {| class="wikitable" |+ Effect editing keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Scroll through options in the effect's menu |- | W,S || Changes the current effect's menu |- | Space || Activates selected option in the effect's menu |- | LMB || Paints effect in the level |- | RMB || Erases effect in the level |- | R || Brush size up |- | F || Brush size down |- | E || Switch to effect stack |- | N || Switch to effect library |} === Camera Editor: === Full article here Camera Editor. N - New camera, spawns held by mouse E - grab a camera if none is held D - Delete held camera P - Place held camera === Light editor: === Full article here [[Light Editor]]. {| class="wikitable" |+ Light editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,A,S,D || Scale current light shape |- | Q,E || Rotate current light shape |- | Z || Toggle between drawing and erasing light |- | LMB || Paint light |- | RMB (hold) || Rotate light shape in direction of mouse ( does not paint it.) |- | R,F || Scroll through light shape library |- | J,L || Change angle of light source |- | I,K || Change distance of light source |} === Prop Editor: === Full article here [[Prop Editor]]. {| class="wikitable" |+ Prop editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A, D || Changes prop library's category |- | W, S || Scrolls through props in current category |- | LMB || Place current prop |- | V (hold) || LMB erases highlighted prop |- | Q,E || Rotate prop left and right |- | Space (hold) || Speed up rotation |- | Y,G,H,J || Stretch prop |- | T || Reset prop stretching |- | R || reset stretching, and rotation |- | Y, H || (on wire/tube props) increases or decreases prop's physics node count. Less means more taught, more means more loose |- | X || Pause wire/tube physics |- | Tab+X+C || clear all props |- | B || Click mouse left to set the highlighted prop as the currently selected prop |- | L || Change layer |- | RMB || Cycle depth in current layer (10 sublevels). |- | Space + RMB || Cycle depth in current layer, reverse direction. |- | U,I,O,P (hold) || Freeform stretch by one of the corners (U - top right, I - bottom right, O - bottom left, and P - top left.) |- | K || resets freeform stretching. |- | N || Switches to editing properties menu of the prop. Things like forcing certain graffiti to be drawn instead of a random one. |- | M (hold) || LMB opens properties of an already placed prop instead of placing a prop (same menu as above) |- | Z || Changes prop color |- | F + LMB/RMB || Changes between prop variants. This only applies to certain props. |} === Environment Editor: === {| class="wikitable" |+ Environment editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | L || Set water level to mouse pointer |- | F || Toggles between drawing water above the first layer or below it. |- | W || Toggle water on level |} == Crash Avoidance and Editor Quirks == Due to the editor being extremely user unfriendly, you are likely to run into various crashes without warning. This is a list of various things to avoid doing. === Crashes: === Do not switch to editing applied effects in the Effects Editor when there are none. The switch will be invisible, and attempting to use the space bar to select something from there will crash the Level Editor. Some effects have very specific conditions and cause issues when rendering, Effects include: Thick Roots, and Shadow Plants. these ones can be okayed through until it renders.) Be sure to remove tiles from parts of a room that will be removed if you resize the room to cut those areas out, those tiles are still recorded, and will crash renders instantly. props are the exact same as above Never render with no cameras. It will crash. Always move the prop menu into an actual category when you open it, it keeps the last menu used, and crashes if you select any entry that is not a real prop. (EX: it will have the effects menu, or tile menu.) If you are using the Mirrored tile placer, in the geometry editor. Placing poles, with the other side of the mirrored brush being outside of the room, will crash the editor. === Quirks: === The main menu is a mess when you return from using the Light Editor or the Environment Editor. Just change to any other editor (geometry or tiles, and back to main menu) to clean it. This is not a crash, but will help prevent confusion if you know to expect this. To use the Move and Move Mirror tools in the editor, you must first select them, and then move your mouse outside of the room itself, before it will respond to your inputs. Usually you will only need to put your mouse over the editor, but in larger rooms, this is often an issue, as the room is "behind" the menu, and thus only changes tool selection. The editor still receives inputs if you only tab out using alt-tab. When viewing another window, it's important to always minimize the editor, because there are many things that can go wrong if you're randomly clicking in the editor. (Requires more confirmation) The screen during rendering should usually show the map being rendered, but it may not. In the task manager, The Rain World Editor is under the tab Adobe Projector. Sometimes the reason it is not showing is a second application called "Print driver host for applications". Closing the application seems to fix the issue. The window for the application may be too big to fit on screen, and cannot be fixed since reaching the top bar or right clicking cannot be accessed to move the window. === Demo and Tutorial Videos === Region Developer Kaeporo created a tutorial for creating levels in and out of the level editor: {{#ev:youtube|YQ0DO-fmPCE|||||urlargs=""}} Mod community member Sacretis also put together a demonstration video, this time covering the creation of a room from scratch to visual polish (massively sped up for the sake of time): {{#ev:youtube|sEE3X1izaJA|||||urlargs=""}} 03a9dac8aed12f8ebc40f4b5b09b7ec963910f05 129 101 2022-08-05T23:29:02Z Dakras 6 wikitext text/x-wiki {{Cleanup}} == The Official Level Editor == The Rain World level editor is a powerful tool that allows the creation of new rooms for the game, and editing existing rooms. It is the same editor the developers used to make all of the rooms for the base game. It takes specially formatted spritesheets and a number of programmed effects and outputs png files that the engine interprets in 3D (as well as an accompanying text file which contains collision and gameplay info). You can download the level editor from [https://ln.sync.com/dl/db7b0cf70/nebg7d6b-qg7gjua7-gjdi94jn-xuvivhw3/view/default/8384962820004 here.] There is also the Community Editor, which is a community-made edit of the original editor, with new features, bugfixes, and better ease of use. There is also Drizzle, a community made level renderer that's hardware accelerated. In the future it intends to replace the existing level editors. === Basic Features Overview === Once you've followed the on-screen instructions for either creating or opening a level, you are presented with the dashboard/preview screen. From here, you can switch between the different editors, load or save your level, and export it for use in-game. The preview presented here requires being manually updated whenever changes are made or when you first open a level. Pressing "1" at any point will bring you back to this screen so you can save your level or switch to a different editor. It's often best to start by modifying the dimensions of the room to your liking using the level size button before beginning to edit. You can change this at any time, but because you set the dimensions manually rather than visually, making changes later is more difficult and poses the risk of accidentally deleting a portion of your room if you aren't careful. From the dashboard you can switch to the Geometry Editor (for defining the level geometry and collision), the Tile Editor (for customizing the tiles and assets that make up the geometry created in the geometry editor), the Effects Editor (for adding procedural effects like erosion or slime, as well as things like plants or chains), the Light Editor (for customizing the light and shadow in your room), or the Prop Editor (for adding additional hand placed props and decals like graffiti). === Controls Overview === ==== View controls (numpad): ==== These are used for every editor view except the Camera and Environment editor to scroll around the screen. Notice, numlock must be turned on for these controls to have any effect. {| class="wikitable" |+ |- ! Key(s) !! Function |- | 8,2,4,6 || Moves view |- | 1 (hold) || Increases view scroll speed. |- | 3 (hold) || Increases view scroll speed even more. |- | 9 (hold) || Allow the view to move outside the boundaries of the level. |} ==== Menu keybinds (Number row): ==== These act as hotkeys to quickly switch between different editor views. These can be used in any editor view as well. {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | 1 || Main menu |- | 2 || Geometry |- | 3 || Tiles |- | 4 || Cameras |- | 5 || Light |- | 6 || Room size |} === Level Settings === ==== Level Size ==== This is where you change how big the level is. You can set the entire level size, and border tiles. Border tiles are padding around the room, mainly for resolutions that are larger than 4:3 It's recomended not to go under the defaults, or your final render will be cut off. ==== Default Medium ==== This determines if you can fall outside of the level or not, death pits still work the same either way however. ==== Light Type ==== The light type can either be set to '''ON''' which will use what you have done in the Light Editor, or '''OFF''' which paints everything in shadow. ==== Seed ==== This is the arrow on the fourth row of bars, which determines what seed the level will use. The seed determines random tile and prop placement, along with how effects are generated. === Rendering === ==== Prioritize Cam ==== This determines what camera will be rendered first, before starting from the beginning. Very useful for re-rendering a specific screen. ==== Text Output ==== This outputs a .txt of the level's geometry, usable in-game. ==== Render Level ==== This renders the screens ==== Mass Render ==== This will render every level in the selected folder. === Editors === <tabber> |-|Geometry Editor= {| class="wikitable" |+ Geometry editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | Arrow keys || Primary cursor scroll through toolbox. If mouse over the toolbox, mouse moves cursor instead. |- | Mouse || Primary cursor movement. |- | LMB || Primary cursor use current tool. |- | Q (hold) || Secondary cursor scroll through toolbox. |- | E,S,D,F || Secondary cursor movement. |- | W || Secondary cursor use current tool. |} |-|Tile Editor= Full article here [[Tile Editor]]. {| class="wikitable" |+ Tile editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Select tile category |- | W,S || Select tile in current category |- | LMB || Place tile under cursor |- | RMB || Erase tile under cursor |- | F (hold) || Use a 3x3 brush for materials |- | V (hold) || Use a 5x5 brush for materials |- | Tab+x+c || Clears all tiles |- | L || Change active layer (1, 2, 3, loop back to 1) |- | E || Sets default material of the room to the currently selected material |- | F (hold) || Enables force placing selected tile (ignoring geometry, erasing colliding tiles) |- | G (hold) || Enables force placing selected tile (forcing appropriate geometry for the tile, erasing colliding tiles) |- | Q || "Eyedropper" (selects tile/material hovered over) |} |-|Effect Editor= Full article here [[Effects Editor]]. {| class="wikitable" |+ Effect library keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Select effect category |- | W,S || Select effect in current category |- | E || Switches to editing applied effects |- | Space || Adds selected effect to the stack |} {| class="wikitable" |+ Applied effect keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,S || Scroll through the effect stack |- | N || Switch to effect library |- | Space || Edit selected effect in the stack |} Effect editing: {| class="wikitable" |+ Effect editing keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Scroll through options in the effect's menu |- | W,S || Changes the current effect's menu |- | Space || Activates selected option in the effect's menu |- | LMB || Paints effect in the level |- | RMB || Erases effect in the level |- | R || Brush size up |- | F || Brush size down |- | E || Switch to effect stack |- | N || Switch to effect library |} |-|Camera Editor= Full article here Camera Editor. N - New camera, spawns held by mouse E - grab a camera if none is held D - Delete held camera P - Place held camera |-|Light editor= Full article here [[Light Editor]]. {| class="wikitable" |+ Light editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,A,S,D || Scale current light shape |- | Q,E || Rotate current light shape |- | Z || Toggle between drawing and erasing light |- | LMB || Paint light |- | RMB (hold) || Rotate light shape in direction of mouse ( does not paint it.) |- | R,F || Scroll through light shape library |- | J,L || Change angle of light source |- | I,K || Change distance of light source |} |-|Prop Editor= Full article here [[Prop Editor]]. {| class="wikitable" |+ Prop editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A, D || Changes prop library's category |- | W, S || Scrolls through props in current category |- | LMB || Place current prop |- | V (hold) || LMB erases highlighted prop |- | Q,E || Rotate prop left and right |- | Space (hold) || Speed up rotation |- | Y,G,H,J || Stretch prop |- | T || Reset prop stretching |- | R || reset stretching, and rotation |- | Y, H || (on wire/tube props) increases or decreases prop's physics node count. Less means more taught, more means more loose |- | X || Pause wire/tube physics |- | Tab+X+C || clear all props |- | B || Click mouse left to set the highlighted prop as the currently selected prop |- | L || Change layer |- | RMB || Cycle depth in current layer (10 sublevels). |- | Space + RMB || Cycle depth in current layer, reverse direction. |- | U,I,O,P (hold) || Freeform stretch by one of the corners (U - top right, I - bottom right, O - bottom left, and P - top left.) |- | K || resets freeform stretching. |- | N || Switches to editing properties menu of the prop. Things like forcing certain graffiti to be drawn instead of a random one. |- | M (hold) || LMB opens properties of an already placed prop instead of placing a prop (same menu as above) |- | Z || Changes prop color |- | F + LMB/RMB || Changes between prop variants. This only applies to certain props. |} |-|Environment Editor= {| class="wikitable" |+ Environment editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | L || Set water level to mouse pointer |- | F || Toggles between drawing water above the first layer or below it. |- | W || Toggle water on level |} </tabber> == Crash Avoidance and Editor Quirks == Due to the editor being extremely user unfriendly, you are likely to run into various crashes without warning. This is a list of various things to avoid doing. === Crashes: === Do not switch to editing applied effects in the Effects Editor when there are none. The switch will be invisible, and attempting to use the space bar to select something from there will crash the Level Editor. Some effects have very specific conditions and cause issues when rendering, Effects include: Thick Roots, and Shadow Plants. these ones can be okayed through until it renders.) Be sure to remove tiles from parts of a room that will be removed if you resize the room to cut those areas out, those tiles are still recorded, and will crash renders instantly. props are the exact same as above Never render with no cameras. It will crash. Always move the prop menu into an actual category when you open it, it keeps the last menu used, and crashes if you select any entry that is not a real prop. (EX: it will have the effects menu, or tile menu.) If you are using the Mirrored tile placer, in the geometry editor. Placing poles, with the other side of the mirrored brush being outside of the room, will crash the editor. === Quirks: === The main menu is a mess when you return from using the Light Editor or the Environment Editor. Just change to any other editor (geometry or tiles, and back to main menu) to clean it. This is not a crash, but will help prevent confusion if you know to expect this. To use the Move and Move Mirror tools in the editor, you must first select them, and then move your mouse outside of the room itself, before it will respond to your inputs. Usually you will only need to put your mouse over the editor, but in larger rooms, this is often an issue, as the room is "behind" the menu, and thus only changes tool selection. The editor still receives inputs if you only tab out using alt-tab. When viewing another window, it's important to always minimize the editor, because there are many things that can go wrong if you're randomly clicking in the editor. (Requires more confirmation) The screen during rendering should usually show the map being rendered, but it may not. In the task manager, The Rain World Editor is under the tab Adobe Projector. Sometimes the reason it is not showing is a second application called "Print driver host for applications". Closing the application seems to fix the issue. The window for the application may be too big to fit on screen, and cannot be fixed since reaching the top bar or right clicking cannot be accessed to move the window. === Demo and Tutorial Videos === Region Developer Kaeporo created a tutorial for creating levels in and out of the level editor: {{#ev:youtube|YQ0DO-fmPCE|||||urlargs=""}} Mod community member Sacretis also put together a demonstration video, this time covering the creation of a room from scratch to visual polish (massively sped up for the sake of time): {{#ev:youtube|sEE3X1izaJA|||||urlargs=""}} 21914a66acd0fac6b208d16de6257e968c18e382 Dev Tools 0 84 102 89 2022-08-05T17:07:59Z Thalber 3 wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ Caption text |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |- | N+Jump || [menus only] Allows you to reposition the layers in the background image with the mouse. |- | B || [menus only] Saves the new positions of the layers to file. |} ==== Menu controls ==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+ Main devtools controls |- ! '''Key''' !! '''Function''' |- | N+Jump || Allows you to reposition the layers in the background image with the mouse. |- | B || Saves the new positions of the layers to file. |} ==== Cutscene controls ==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+ Cutscene controls |- ! '''Key''' !! '''Function''' |- | M || Activate/Deactivate cutscene editing mode. |- | Left Click || Select and drag keyframes around. |- | J || Add a new keyframe. |- | K || Remove a keyframe. |- | O || Change depth of selected keyframe. |- | L || Offset all keyframes. |- | I || Test playback of cutscene. |} </div> === Main Interface Tabs === Once opening the main dev tools interface with H, the interface is broken up into five different tabs. Each of these tabs are extensive enough to warrant their own pages: * [[Room Settings Tab]] * [[Objects Tab]] * [[Sound Tab]] * [[Map Tab]] * [[Triggers Tab]] [[Category:Devtools]] b1cd88f3c46f69687874ea314ea668100f5af6c8 116 102 2022-08-05T20:16:48Z Thalber 3 Add tabber, add tab for room settings wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ===Interface Tabs=== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. <div> <tabber> |-| Room settings ====General Controls==== {| class="wikitable" |+ |- | Pages || Brings you to the other devtool editors. |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! Control !! Function |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === [[File:Fadepalette example.png]] ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! Control !! Function |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image on the right shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! {| class="wikitable" |- ! Effect !! Description |- | SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. |- | SkyBloom || Increases how fuzzy/bloomy the sky's light is. |- | LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. |- | Bloom || Similar to SkyBloom, but applies to lights. |- | Fog || Creates a white cloudy effect at layer 1. Not compatible with |- | Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- |- | GreenSparks || Underhang, and the Legs' green sparkles. |- | VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | Flies || Spawns small flys that buzz around the room and land on objects. |- | FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | TinyDragonFly || Spawns tiny bugs that fly around plants. |- | RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | Ant || Spawns small jumping bugs. |- | Beetle || Spawns small beetles that slowly fly around the room. |- | WaterGlowWorm || Spawns small worms that swim around in water. |- | Wasp || Spawns small wasps that quickly dart between walls. |- | Moth || Spawns small white moths which slowly flutter around the room. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom`, VoidMelt </syntaxhighlight> |-| Objects |-| Sounds |-| Map |-| Triggers </tabber> <div> [[Category:Devtools]] 30b7f21089bbbea00c184fc44a8c1eda1aa9ae9a 117 116 2022-08-05T20:48:01Z Thalber 3 dd tab for objects wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ===Interface Tabs=== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. <div> <tabber> |-| Room settings === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === [[File:Fadepalette example.png]] ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image on the right shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! {|class="wikitable" |- ! '''Effect''' !! '''Description''' |- | SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. |- | SkyBloom || Increases how fuzzy/bloomy the sky's light is. |- | LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. |- | Bloom || Similar to SkyBloom, but applies to lights. |- | Fog || Creates a white cloudy effect at layer 1. Not compatible with |- | Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- |- | GreenSparks || Underhang, and the Legs' green sparkles. |- | VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | Flies || Spawns small flys that buzz around the room and land on objects. |- | FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | TinyDragonFly || Spawns tiny bugs that fly around plants. |- | RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | Ant || Spawns small jumping bugs. |- | Beetle || Spawns small beetles that slowly fly around the room. |- | WaterGlowWorm || Spawns small worms that swim around in water. |- | Wasp || Spawns small wasps that quickly dart between walls. |- | Moth || Spawns small white moths which slowly flutter around the room. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom`, VoidMelt </syntaxhighlight> |-| Objects === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. <span id="mouse-input"></span> === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. <span id="object-library"></span> == Object Library == ----- {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds |-| Map |-| Triggers </tabber> <div> [[Category:Devtools]] 409e58b882793588ee1deab15e6245714a58147a 118 117 2022-08-05T21:07:12Z Thalber 3 wikitext text/x-wiki ===Interface Tabs=== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. == == <tabber> |-| Room settings == == <div> === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === [[File:Fadepalette example.png]] ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image on the right shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! {|class="wikitable" |- ! '''Effect''' !! '''Description''' |- | SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. |- | SkyBloom || Increases how fuzzy/bloomy the sky's light is. |- | LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. |- | Bloom || Similar to SkyBloom, but applies to lights. |- | Fog || Creates a white cloudy effect at layer 1. Not compatible with |- | Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- |- | GreenSparks || Underhang, and the Legs' green sparkles. |- | VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | Flies || Spawns small flys that buzz around the room and land on objects. |- | FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | TinyDragonFly || Spawns tiny bugs that fly around plants. |- | RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | Ant || Spawns small jumping bugs. |- | Beetle || Spawns small beetles that slowly fly around the room. |- | WaterGlowWorm || Spawns small worms that swim around in water. |- | Wasp || Spawns small wasps that quickly dart between walls. |- | Moth || Spawns small white moths which slowly flutter around the room. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom`, VoidMelt </syntaxhighlight> |-| Objects == == Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds == == [[File:soundTab]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map |-| Triggers </tabber> <div> [[Category:Devtools]] 5785dbaf4bb8804459ba510559509f2880f52025 119 118 2022-08-05T21:10:25Z Thalber 3 Undo revision 118 by [[Special:Contributions/Thalber|Thalber]] ([[User talk:Thalber|talk]]) wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ===Interface Tabs=== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. <div> <tabber> |-| Room settings === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === [[File:Fadepalette example.png]] ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image on the right shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! {|class="wikitable" |- ! '''Effect''' !! '''Description''' |- | SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. |- | SkyBloom || Increases how fuzzy/bloomy the sky's light is. |- | LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. |- | Bloom || Similar to SkyBloom, but applies to lights. |- | Fog || Creates a white cloudy effect at layer 1. Not compatible with |- | Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- |- | GreenSparks || Underhang, and the Legs' green sparkles. |- | VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | Flies || Spawns small flys that buzz around the room and land on objects. |- | FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | TinyDragonFly || Spawns tiny bugs that fly around plants. |- | RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | Ant || Spawns small jumping bugs. |- | Beetle || Spawns small beetles that slowly fly around the room. |- | WaterGlowWorm || Spawns small worms that swim around in water. |- | Wasp || Spawns small wasps that quickly dart between walls. |- | Moth || Spawns small white moths which slowly flutter around the room. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom`, VoidMelt </syntaxhighlight> |-| Objects === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. <span id="mouse-input"></span> === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. <span id="object-library"></span> == Object Library == ----- {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds |-| Map |-| Triggers </tabber> <div> [[Category:Devtools]] 409e58b882793588ee1deab15e6245714a58147a 120 119 2022-08-05T21:12:28Z Thalber 3 Add sound tab wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ===Interface Tabs=== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. == == <tabber> |-| Room settings == == <div> === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === [[File:Fadepalette example.png]] ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image on the right shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! {|class="wikitable" |- ! '''Effect''' !! '''Description''' |- | SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. |- | SkyBloom || Increases how fuzzy/bloomy the sky's light is. |- | LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. |- | Bloom || Similar to SkyBloom, but applies to lights. |- | Fog || Creates a white cloudy effect at layer 1. Not compatible with |- | Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- |- | GreenSparks || Underhang, and the Legs' green sparkles. |- | VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | Flies || Spawns small flys that buzz around the room and land on objects. |- | FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | TinyDragonFly || Spawns tiny bugs that fly around plants. |- | RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | Ant || Spawns small jumping bugs. |- | Beetle || Spawns small beetles that slowly fly around the room. |- | WaterGlowWorm || Spawns small worms that swim around in water. |- | Wasp || Spawns small wasps that quickly dart between walls. |- | Moth || Spawns small white moths which slowly flutter around the room. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom`, VoidMelt </syntaxhighlight> |-| Objects == == Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds == == [[File:soundTab]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map |-| Triggers </tabber> <div> [[Category:Devtools]] 2e76da131c675bfc1b09c0ff6702608bfa11ae57 121 120 2022-08-05T21:21:38Z Thalber 3 Port Map tab wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ===Interface Tabs=== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. == == <tabber> |-| Room settings == == <div> === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === [[File:Fadepalette example.png]] ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image on the right shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! {|class="wikitable" |- ! '''Effect''' !! '''Description''' |- | SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. |- | SkyBloom || Increases how fuzzy/bloomy the sky's light is. |- | LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. |- | Bloom || Similar to SkyBloom, but applies to lights. |- | Fog || Creates a white cloudy effect at layer 1. Not compatible with |- | Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- |- | GreenSparks || Underhang, and the Legs' green sparkles. |- | VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | Flies || Spawns small flys that buzz around the room and land on objects. |- | FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | TinyDragonFly || Spawns tiny bugs that fly around plants. |- | RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | Ant || Spawns small jumping bugs. |- | Beetle || Spawns small beetles that slowly fly around the room. |- | WaterGlowWorm || Spawns small worms that swim around in water. |- | Wasp || Spawns small wasps that quickly dart between walls. |- | Moth || Spawns small white moths which slowly flutter around the room. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom`, VoidMelt </syntaxhighlight> |-| Objects == == Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds == == [[File:soundTab]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map == == == '''''<u>This section contains outdated information and needs to be updated!</u>''''' == [[File:mapTab]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. <span id="create-def.-mat.-rectangle"></span> === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers </tabber> <div> [[Category:Devtools]] 7564f136fbf130460f64e8615789ecfeaee3068e 122 121 2022-08-05T21:44:28Z Thalber 3 Port triggers tab wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ===Interface Tabs=== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. == == <tabber> |-| Room settings == == <div> === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === [[File:Fadepalette example.png]] ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image on the right shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! {|class="wikitable" |- ! '''Effect''' !! '''Description''' |- | SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. |- | SkyBloom || Increases how fuzzy/bloomy the sky's light is. |- | LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. |- | Bloom || Similar to SkyBloom, but applies to lights. |- | Fog || Creates a white cloudy effect at layer 1. Not compatible with |- | Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- |- | GreenSparks || Underhang, and the Legs' green sparkles. |- | VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | Flies || Spawns small flys that buzz around the room and land on objects. |- | FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | TinyDragonFly || Spawns tiny bugs that fly around plants. |- | RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | Ant || Spawns small jumping bugs. |- | Beetle || Spawns small beetles that slowly fly around the room. |- | WaterGlowWorm || Spawns small worms that swim around in water. |- | Wasp || Spawns small wasps that quickly dart between walls. |- | Moth || Spawns small white moths which slowly flutter around the room. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom`, VoidMelt </syntaxhighlight> |-| Objects == == Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds == == [[File:soundTab.png|400px|right|border|]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map == == == '''''<u>This section contains outdated information and needs to be updated!</u>''''' == [[File:mapTab.png|400px|right|border|]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections.png|400px|right|border|Connections on dev map]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png|400px|right|border|Canon view of the map]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png|400px|right|border|Example of a rendered map .png file]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers == == = '''''<u>This section contains outdated information and needs to be updated!</u>''''' = [[File:triggerTab.png|600px|right|border|Trigger tab view]] <span id="general-controls"></span> == General controls == === Save: === Saves the current effects and room settings to a file inside the region’s World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by pressing R and returning to the room to see the changes. === Inherent from template: === Will set the values stored in a specific template the region has to this room. === Save as template: === Saves the current room’s settings as a template for easy re-use. == Triggers Menu == '''Triggers''' are the mechanism in which some in-game events occur, such as specific songs playing, projections being displayed by the player guide overseer, or information text being displayed at the bottom of the screen. Clicking one of the four options in the bottom right-hand box will place a trigger of that type, which can be moved just like other devtools objects. === Trigger Options === Triggers have a number of settings which determine what the trigger does and under what circumstances. {| class="wikitable" |+ |- ! Trigger setting !! Description |- | Active from cycle || The minimum total cycle requirement for the trigger to activate. |- | Active up to cycle || The maximum cycle limit for the trigger to activate - if the player has a cycle count higher than this number, the trigger will not activate. |- | Fire chance || A random percentage chance for the trigger to activate, from 0% to 100%. |- | Trigger delay || How many seconds between the requirements for the trigger being met and the event occurring. |- | Karma req || The minimum karma the player needs for the trigger to activate (from 0 to 5) |- | Can only fire once/Can fire multiple times || Self-explanatory, determines whether the trigger only fires once or not. |- | No entrance requirement/Entrance XX || Determines whether the player can enter from any entrance pipe, or whether they need to come through a specific one. When an entrance is selected, a red line will connect this entrance and the options box. |- | White, Yellow, Red || Determines which gamemodes the trigger fires on - Survivor, Hunter or Monk. A gamemode’s name being displayed means that the trigger will fire in said gamemode. |} === Event Types === The lowest button on the options box lets you pick what type of event you want to add. ==== MusicEvent ==== Plays a song from the soundtrack. * The first button lets you pick the song you want to play. Files for these songs can be found in *Rain World, or many of them can be found [https://www.youtube.com/playlist?list=PLPJWSVeszYFBo1oAXYgzGfJfewnGKgGna online.] {| class="wikitable" |+ MusicEvent options |- ! Option !! Description |- | Play volume || The volume the song plays at. |- | Fade in || In seconds, how long the song takes to reach full volume. |- | Song priority || If this song’s priority is higher than another’s, then this song will continue to play if the other trigger is activated. If the priority is lower, then the higher one will play instead of it. |- | Drone volume || WIP, presumably adds a background drone sound at the set volume. |- | Fade out at threat || The threat level at which the song fades out and is overtaken by the threat music. |- | Rest cycles || If this trigger can activate multiple times, the number of cycles for the trigger to wait before being able to fire again. |- | Room transitions || How many rooms the song will continue playing through. |- | One song per cycle || Whether or not the same song can activate multiple times in one cycle. |- | Play once/loop || Determines whether the song plays once or loops |- | Continue at death || Continue playing the song when the player dies. |- | Continue through gate || Continue playing the song when the player uses a region gate. |} ==== StopMusicEvent ==== As the name says, stops one or more MusicEvents. The first button lets you pick the song you want to stop/exclude. * '''Priority:''' If a song has a higher priority than the trigger, it won’t stop. * '''Fade out:''' Same as fade in, but fading out to silence. * '''Stop all songs/stop specific song/stop all but specific song:''' Self-explanatory, song selected at the top of the box is what this refers to. ==== '''PoleMimicSubtleReveal''' ==== Causes a pole mimic to flutter slightly when activated. ==== '''ShowProjectedImageEvent''' ==== Shows player guide overseer projections ==== '''RoomSpecificTextMessage''' ==== Causes specific text prompt to appear. Prompts are hardcoded by room name {{Cn}} ==== '''BringPlayerGuideToRoom''' ==== Forces player overseer to current room === Trigger Types === * '''Spot:''' The most commonly used trigger; activates when slugcat walks into a specific circular area of the room. This is indicated by a white area-of-effect which can be moved and scaled. * '''SeeCreature:''' ''WIP, presumably activates upon a certain creature being seen.'' * '''RegionBump:''' Activates either when the region is entered or at the beginning of a cycle where the region name and cycle count is shown. * '''PreRegionBump:''' Seemingly functions the same way as RegionBump. </tabber> <div> [[Category:Devtools]] 05bcf40672de941cda692a84e2349afb0fb83fd3 EnumExtender 0 94 103 2022-08-05T17:35:22Z Thalber 3 Created page with "<nowiki>[https://beestuff.pythonanywhere.com/audb/api/mods/0/1/download/latest EnumExtender]</nowiki> is a tool mod by bee, which allows you to add more items in `enum`s much easier. == How to Use == First, create a `public static class` with a name starts with `EnumExt_`. EnumExtender will automatically detect any class in your assembly with that keyword. Then create a field with the type of enum you want to extend, and item name for the field name.<syntaxhighlight l..." wikitext text/x-wiki <nowiki>[https://beestuff.pythonanywhere.com/audb/api/mods/0/1/download/latest EnumExtender]</nowiki> is a tool mod by bee, which allows you to add more items in `enum`s much easier. == How to Use == First, create a `public static class` with a name starts with `EnumExt_`. EnumExtender will automatically detect any class in your assembly with that keyword. Then create a field with the type of enum you want to extend, and item name for the field name.<syntaxhighlight lang="csharp"> public static class EnumExt_MyMod { // You can have multiple EnumExt_ classes in your assembly if you need multiple items with the same name for the different enum public static CreatureCommnuities.CommunityID Vultures; public static SlugcatStats.Name YellowishWhite; public static SlugcatStats.Name WhitishYellow; } </syntaxhighlight> To access these new enum items, instead of `[enum].[item]`, use that static field. To compare it, use `if` statements.<syntaxhighlight lang="csharp"> public static SlugStatsPatch(On.SlugcatStats.orig_ctor orig, SlugcatStats stats, int slugcatNumber, bool malnourished) {     orig.Invoke(stats, slugcatNumber, malnourished);     if (stats.name == EnumExt_MyMod.YellowishWhite)     {         stats.runspeedFac = 1.2f;         stats.poleClimbSpeedFac = 1.25f;         stats.corridorClimbSpeedFac = 1.2f;     } } </syntaxhighlight> However, if EnumExtender is not present in runtime (for instance, the user forgot to install EnumExtender), these fields won't be initialized and will stay 0. This can be used to detect whether EnumExtender is installed or not.<syntaxhighlight lang="csharp"> public static bool HasEnumExt => (int)EnumExt_MyMod.YellowishWhite > 0; // This value turns true after EnumExtender initializes (after OnEnable) </syntaxhighlight> When you have multiple new items, you can also try something like this.<syntaxhighlight lang="csharp"> public static class EnumSwitch {     public enum SlugcatStatsName     {         DEFAULT = -1, // unrelated to this mod         YellowishWhite,         WhitishYellow     };     public static SlugcatStatsName GetSlugcatStatsName(SlugcatStats.Name name)     {         if (!HasEnumExt) { return SlugcatStatsName.DEFAULT; } // EnumExt is not installed         if (name == EnumExt_MyMod.YellowishWhite) { return SlugcatStatsName.YellowishWhite; }         if (name == EnumExt_MyMod.WhitishYellow) { return SlugcatStatsName.WhitishYellow; }         return SlugcatStatsName.DEFAULT;     } } </syntaxhighlight> And when you need to use switch later,<syntaxhighlight lang="csharp"> switch (EnumSwitch.GetSlugcatStatsName(name)) {     default:     case SlugcatStatsName.DEFAULT: break;     case SlugcatStatsName.YellowishWhite:         break;     case SlugcatStatsName.WhitishYellow:         break; } </syntaxhighlight> That's about it. This mod is really easy to use and understand, but as many things in Rain World is set in `enum`s, having an ability to edit them grants so much potential. c354a63abf14d989b0384c6055d8efafe35a63aa 104 103 2022-08-05T17:37:56Z Thalber 3 wikitext text/x-wiki [https://beestuff.pythonanywhere.com/audb/api/mods/0/1/download/latest EnumExtender] is a tool mod by bee, which allows you to add more items in `enum`s much easier. == How to Use == First, create a `public static class` with a name starts with `EnumExt_`. EnumExtender will automatically detect any class in your assembly with that keyword. Then create a field with the type of enum you want to extend, and item name for the field name. <syntaxhighlight lang="csharp"> public static class EnumExt_MyMod { // You can have multiple EnumExt_ classes in your assembly if you need multiple items with the same name for the different enum public static CreatureCommnuities.CommunityID Vultures; public static SlugcatStats.Name YellowishWhite; public static SlugcatStats.Name WhitishYellow; } </syntaxhighlight> To access these new enum items, instead of `[enum].[item]`, use that static field. To compare it, use `if` statements. <syntaxhighlight lang="csharp"> public static SlugStatsPatch(On.SlugcatStats.orig_ctor orig, SlugcatStats stats, int slugcatNumber, bool malnourished) {     orig.Invoke(stats, slugcatNumber, malnourished);     if (stats.name == EnumExt_MyMod.YellowishWhite)     {         stats.runspeedFac = 1.2f;         stats.poleClimbSpeedFac = 1.25f;         stats.corridorClimbSpeedFac = 1.2f;     } } </syntaxhighlight> However, if EnumExtender is not present in runtime (for instance, the user forgot to install EnumExtender), these fields won't be initialized and will stay 0. This can be used to detect whether EnumExtender is installed or not. <syntaxhighlight lang="csharp"> public static bool HasEnumExt => (int)EnumExt_MyMod.YellowishWhite > 0; // This value turns true after EnumExtender initializes (after OnEnable) </syntaxhighlight> When you have multiple new items, you can also try something like this. <syntaxhighlight lang="csharp"> public static class EnumSwitch {     public enum SlugcatStatsName     {         DEFAULT = -1, // unrelated to this mod         YellowishWhite,         WhitishYellow     };     public static SlugcatStatsName GetSlugcatStatsName(SlugcatStats.Name name)     {         if (!HasEnumExt) { return SlugcatStatsName.DEFAULT; } // EnumExt is not installed         if (name == EnumExt_MyMod.YellowishWhite) { return SlugcatStatsName.YellowishWhite; }         if (name == EnumExt_MyMod.WhitishYellow) { return SlugcatStatsName.WhitishYellow; }         return SlugcatStatsName.DEFAULT;     } } </syntaxhighlight> And when you need to use switch later, <syntaxhighlight lang="csharp"> switch (EnumSwitch.GetSlugcatStatsName(name)) {     default:     case SlugcatStatsName.DEFAULT: break;     case SlugcatStatsName.YellowishWhite:         break;     case SlugcatStatsName.WhitishYellow:         break; } </syntaxhighlight> That's about it. This mod is really easy to use and understand, but as many things in Rain World is set in `enum`s, having an ability to edit them grants so much potential. becfaf05fb7e1ed32c7c7c469a18de1400befd0f 105 104 2022-08-05T17:44:03Z Thalber 3 wikitext text/x-wiki [https://beestuff.pythonanywhere.com/audb/api/mods/0/1/download/latest EnumExtender] is a tool mod by bee, which allows you to add more items in `enum`s much easier. == How to Use == First, create a `public static class` with a name starts with <code>EnumExt_</code>. EnumExtender will automatically detect any class in your assembly with that keyword. Then create a field with the type of enum you want to extend, and item name for the field name. <syntaxhighlight lang="csharp"> public static class EnumExt_MyMod { // You can have multiple EnumExt_ classes in your assembly if you need multiple items with the same name for the different enum public static CreatureCommnuities.CommunityID Vultures; public static SlugcatStats.Name YellowishWhite; public static SlugcatStats.Name WhitishYellow; } </syntaxhighlight> To access these new enum items, instead of <code>[enum].[item]</code>, use that static field. To compare it, use <code>if</code> statements. <syntaxhighlight lang="csharp"> public static SlugStatsPatch(On.SlugcatStats.orig_ctor orig, SlugcatStats stats, int slugcatNumber, bool malnourished) {     orig.Invoke(stats, slugcatNumber, malnourished);     if (stats.name == EnumExt_MyMod.YellowishWhite)     {         stats.runspeedFac = 1.2f;         stats.poleClimbSpeedFac = 1.25f;         stats.corridorClimbSpeedFac = 1.2f;     } } </syntaxhighlight> However, if EnumExtender is not present in runtime (for instance, the user forgot to install EnumExtender), these fields won't be initialized and will stay 0. This can be used to detect whether EnumExtender is installed or not. <syntaxhighlight lang="csharp"> public static bool HasEnumExt => (int)EnumExt_MyMod.YellowishWhite > 0; // This value turns true after EnumExtender initializes (after OnEnable) </syntaxhighlight> When you have multiple new items, you can also try something like this. <syntaxhighlight lang="csharp"> public static class EnumSwitch {     public enum SlugcatStatsName     {         DEFAULT = -1, // unrelated to this mod         YellowishWhite,         WhitishYellow     };     public static SlugcatStatsName GetSlugcatStatsName(SlugcatStats.Name name)     {         if (!HasEnumExt) { return SlugcatStatsName.DEFAULT; } // EnumExt is not installed         if (name == EnumExt_MyMod.YellowishWhite) { return SlugcatStatsName.YellowishWhite; }         if (name == EnumExt_MyMod.WhitishYellow) { return SlugcatStatsName.WhitishYellow; }         return SlugcatStatsName.DEFAULT;     } } </syntaxhighlight> And when you need to use switch later, <syntaxhighlight lang="csharp"> switch (EnumSwitch.GetSlugcatStatsName(name)) {     default:     case SlugcatStatsName.DEFAULT: break;     case SlugcatStatsName.YellowishWhite:         break;     case SlugcatStatsName.WhitishYellow:         break; } </syntaxhighlight> That's about it. This mod is really easy to use and understand, but as many things in Rain World is set in `enum`s, having an ability to edit them grants so much potential. 8ffaebf6feff6a8f3dc5aa090dd1451995d50001 111 105 2022-08-05T18:13:39Z Thalber 3 wikitext text/x-wiki [https://beestuff.pythonanywhere.com/audb/api/mods/0/1/download/latest EnumExtender] is a tool mod by bee, which allows you to add more items in `enum`s much easier. == How to Use == First, create a `public static class` with a name starts with <code>EnumExt_</code>. EnumExtender will automatically detect any class in your assembly with that keyword. Then create a field with the type of enum you want to extend, and item name for the field name. <syntaxhighlight lang="csharp"> public static class EnumExt_MyMod { // You can have multiple EnumExt_ classes in your assembly if you need multiple items with the same name for the different enum public static CreatureCommnuities.CommunityID Vultures; public static SlugcatStats.Name YellowishWhite; public static SlugcatStats.Name WhitishYellow; } </syntaxhighlight> To access these new enum items, instead of <code>[enum].[item]</code>, use that static field. To compare it, use <code>if</code> statements. <syntaxhighlight lang="csharp"> public static SlugStatsPatch(On.SlugcatStats.orig_ctor orig, SlugcatStats stats, int slugcatNumber, bool malnourished) {     orig.Invoke(stats, slugcatNumber, malnourished);     if (stats.name == EnumExt_MyMod.YellowishWhite)     {         stats.runspeedFac = 1.2f;         stats.poleClimbSpeedFac = 1.25f;         stats.corridorClimbSpeedFac = 1.2f;     } } </syntaxhighlight> However, if EnumExtender is not present in runtime (for instance, the user forgot to install EnumExtender), these fields won't be initialized and will stay 0. This can be used to detect whether EnumExtender is installed or not. <syntaxhighlight lang="csharp"> public static bool HasEnumExt => (int)EnumExt_MyMod.YellowishWhite > 0; // This value turns true after EnumExtender initializes (after OnEnable) </syntaxhighlight> When you have multiple new items, you can also try something like this. <syntaxhighlight lang="csharp"> public static class EnumSwitch {     public enum SlugcatStatsName     {         DEFAULT = -1, // unrelated to this mod         YellowishWhite,         WhitishYellow     };     public static SlugcatStatsName GetSlugcatStatsName(SlugcatStats.Name name)     {         if (!HasEnumExt) { return SlugcatStatsName.DEFAULT; } // EnumExt is not installed         if (name == EnumExt_MyMod.YellowishWhite) { return SlugcatStatsName.YellowishWhite; }         if (name == EnumExt_MyMod.WhitishYellow) { return SlugcatStatsName.WhitishYellow; }         return SlugcatStatsName.DEFAULT;     } } </syntaxhighlight> And when you need to use switch later, <syntaxhighlight lang="csharp"> switch (EnumSwitch.GetSlugcatStatsName(name)) {     default:     case SlugcatStatsName.DEFAULT: break;     case SlugcatStatsName.YellowishWhite:         break;     case SlugcatStatsName.WhitishYellow:         break; } </syntaxhighlight> That's about it. This mod is really easy to use and understand, but as many things in Rain World is set in `enum`s, having an ability to edit them grants so much potential. [[Category:Code Mods]] b51276b18b9f99297ae95fa67d4e1722984ac267 112 111 2022-08-05T18:32:30Z Thalber 3 wikitext text/x-wiki {{Cleanup}} [https://beestuff.pythonanywhere.com/audb/api/mods/0/1/download/latest EnumExtender] is a tool mod by bee, which allows you to add more items in `enum`s much easier. == How to Use == First, create a <code>public static class</code> with a name starts with <code>EnumExt_</code>. EnumExtender will automatically detect any class in your assembly with that keyword. Then create a field with the type of enum you want to extend, and item name for the field name. <syntaxhighlight lang="csharp"> public static class EnumExt_MyMod { // You can have multiple EnumExt_ classes in your assembly if you need multiple items with the same name for the different enum public static CreatureCommnuities.CommunityID Vultures; public static SlugcatStats.Name YellowishWhite; public static SlugcatStats.Name WhitishYellow; } </syntaxhighlight> To access these new enum items, instead of <code>[enum].[item]</code>, use that static field. To compare it, use <code>if</code> statements. <syntaxhighlight lang="csharp"> public static SlugStatsPatch(On.SlugcatStats.orig_ctor orig, SlugcatStats stats, int slugcatNumber, bool malnourished) {     orig.Invoke(stats, slugcatNumber, malnourished);     if (stats.name == EnumExt_MyMod.YellowishWhite)     {         stats.runspeedFac = 1.2f;         stats.poleClimbSpeedFac = 1.25f;         stats.corridorClimbSpeedFac = 1.2f;     } } </syntaxhighlight> However, if EnumExtender is not present in runtime (for instance, the user forgot to install EnumExtender), these fields won't be initialized and will stay 0. This can be used to detect whether EnumExtender is installed or not. <syntaxhighlight lang="csharp"> public static bool HasEnumExt => (int)EnumExt_MyMod.YellowishWhite > 0; // This value turns true after EnumExtender initializes (after OnEnable) </syntaxhighlight> When you have multiple new items, you can also try something like this. <syntaxhighlight lang="csharp"> public static class EnumSwitch {     public enum SlugcatStatsName     {         DEFAULT = -1, // unrelated to this mod         YellowishWhite,         WhitishYellow     };     public static SlugcatStatsName GetSlugcatStatsName(SlugcatStats.Name name)     {         if (!HasEnumExt) { return SlugcatStatsName.DEFAULT; } // EnumExt is not installed         if (name == EnumExt_MyMod.YellowishWhite) { return SlugcatStatsName.YellowishWhite; }         if (name == EnumExt_MyMod.WhitishYellow) { return SlugcatStatsName.WhitishYellow; }         return SlugcatStatsName.DEFAULT;     } } </syntaxhighlight> And when you need to use switch later, <syntaxhighlight lang="csharp"> switch (EnumSwitch.GetSlugcatStatsName(name)) {     default:     case SlugcatStatsName.DEFAULT: break;     case SlugcatStatsName.YellowishWhite:         break;     case SlugcatStatsName.WhitishYellow:         break; } </syntaxhighlight> That's about it. This mod is really easy to use and understand, but as many things in Rain World is set in `enum`s, having an ability to edit them grants so much potential. [[Category:Code Mods]] a66a7a076fd3b74f6f7bf7433b36fdb9ac8cd018 113 112 2022-08-05T18:33:13Z Thalber 3 wikitext text/x-wiki {{Cleanup}} [https://beestuff.pythonanywhere.com/audb/api/mods/0/1/download/latest EnumExtender] is a tool mod by bee, which allows you to add more items in enums much easier. == How to Use == First, create a <code>public static class</code> with a name starts with <code>EnumExt_</code>. EnumExtender will automatically detect any class in your assembly with that keyword. Then create a field with the type of enum you want to extend, and item name for the field name. <syntaxhighlight lang="csharp"> public static class EnumExt_MyMod { // You can have multiple EnumExt_ classes in your assembly if you need multiple items with the same name for the different enum public static CreatureCommnuities.CommunityID Vultures; public static SlugcatStats.Name YellowishWhite; public static SlugcatStats.Name WhitishYellow; } </syntaxhighlight> To access these new enum items, instead of <code>[enum].[item]</code>, use that static field. To compare it, use <code>if</code> statements. <syntaxhighlight lang="csharp"> public static SlugStatsPatch(On.SlugcatStats.orig_ctor orig, SlugcatStats stats, int slugcatNumber, bool malnourished) {     orig.Invoke(stats, slugcatNumber, malnourished);     if (stats.name == EnumExt_MyMod.YellowishWhite)     {         stats.runspeedFac = 1.2f;         stats.poleClimbSpeedFac = 1.25f;         stats.corridorClimbSpeedFac = 1.2f;     } } </syntaxhighlight> However, if EnumExtender is not present in runtime (for instance, the user forgot to install EnumExtender), these fields won't be initialized and will stay 0. This can be used to detect whether EnumExtender is installed or not. <syntaxhighlight lang="csharp"> public static bool HasEnumExt => (int)EnumExt_MyMod.YellowishWhite > 0; // This value turns true after EnumExtender initializes (after OnEnable) </syntaxhighlight> When you have multiple new items, you can also try something like this. <syntaxhighlight lang="csharp"> public static class EnumSwitch {     public enum SlugcatStatsName     {         DEFAULT = -1, // unrelated to this mod         YellowishWhite,         WhitishYellow     };     public static SlugcatStatsName GetSlugcatStatsName(SlugcatStats.Name name)     {         if (!HasEnumExt) { return SlugcatStatsName.DEFAULT; } // EnumExt is not installed         if (name == EnumExt_MyMod.YellowishWhite) { return SlugcatStatsName.YellowishWhite; }         if (name == EnumExt_MyMod.WhitishYellow) { return SlugcatStatsName.WhitishYellow; }         return SlugcatStatsName.DEFAULT;     } } </syntaxhighlight> And when you need to use switch later, <syntaxhighlight lang="csharp"> switch (EnumSwitch.GetSlugcatStatsName(name)) {     default:     case SlugcatStatsName.DEFAULT: break;     case SlugcatStatsName.YellowishWhite:         break;     case SlugcatStatsName.WhitishYellow:         break; } </syntaxhighlight> That's about it. This mod is really easy to use and understand, but as many things in Rain World is set in `enum`s, having an ability to edit them grants so much potential. [[Category:Code Mods]] 62e3bf76d5a8f87146469cefdb5c48bedcaa84f9 144 113 2022-08-06T20:41:30Z Thalber 3 wikitext text/x-wiki {{Cleanup}} '''[https://beestuff.pythonanywhere.com/audb/api/mods/0/1/download/latest EnumExtender]''' or '''EE''' is a tool mod which allows adding entries to <code>Enum</code>s. It is widely used as a dependency library. == Features == === Automatic extension === ''Using this feature does not require referencing EE assembly in your project.'' On initialization, EE scans all loaded classes, looking for <code>public static class</code> with names starting with <code>EnumExt_</code>. Extensions are created from <code>public static</code> fields with the type of target enum. Created entries have the same name as the field, and the field gets the value of the new entry. Example use: <syntaxhighlight lang="csharp"> public static class EnumExt_MyMod { // You can have multiple EnumExt_ classes in your assembly if you need multiple items with the same name for the different enum //this adds entry "Vultures" to enum "CreatureCommnuities.CommunityID" public static CreatureCommnuities.CommunityID Vultures; //this adds "YellowishWhite" to "SlugcatStats.Name" public static SlugcatStats.Name YellowishWhite; public static SlugcatStats.Name WhitishYellow; } </syntaxhighlight> To access these new enum items, instead of <code>[enum].[item]</code>, use that static field. To compare it, use <code>if</code> statements (unfortunately, you can not use static fields for branches in a <code>switch</code> statement). Example use: <syntaxhighlight lang="csharp"> public static SlugStatsPatch(On.SlugcatStats.orig_ctor orig, SlugcatStats stats, int slugcatNumber, bool malnourished) {     orig.Invoke(stats, slugcatNumber, malnourished);     if (stats.name == EnumExt_MyMod.YellowishWhite)     {         stats.runspeedFac = 1.2f;         stats.poleClimbSpeedFac = 1.25f;         stats.corridorClimbSpeedFac = 1.2f;     } } </syntaxhighlight> However, if EnumExtender is not present in runtime (for instance, the user forgot to install EnumExtender), these fields won't be initialized and will always stay at 0. This can be used to easily detect whether EnumExtender is installed or not. <syntaxhighlight lang="csharp"> public static bool HasEnumExt => (int)EnumExt_MyMod.YellowishWhite > 0; // This property returns true after EE initializes (after OnEnable) </syntaxhighlight> ==== Switch statement workaround ==== If you have multiple new items and really want to use switches, you can do something like the following: <syntaxhighlight lang="csharp"> public static class EnumSwitch { //the intermediary enum     public enum SlugcatStatsName     {         DEFAULT = -1, // unrelated to this mod         YellowishWhite,         WhitishYellow     };     public static SlugcatStatsName GetSlugStatsNameInterm(SlugcatStats.Name name)     {         if (!HasEnumExt) { return SlugcatStatsName.DEFAULT; } // EnumExt is not installed         if (name == EnumExt_MyMod.YellowishWhite) { return SlugcatStatsName.YellowishWhite; }         if (name == EnumExt_MyMod.WhitishYellow) { return SlugcatStatsName.WhitishYellow; }         return SlugcatStatsName.DEFAULT;     } } </syntaxhighlight> And when you need to use switch later, <syntaxhighlight lang="csharp"> switch (EnumSwitch.GetSlugStatsNameInterm(name)) {     default:     case SlugcatStatsName.DEFAULT: break;     case SlugcatStatsName.YellowishWhite:         break;     case SlugcatStatsName.WhitishYellow:         break; } </syntaxhighlight> <!--ehhhh this was a bad idea '''Alternatively''', if you want to use one switch statement containing checks for both vanilla and intermediary enum, you can # give an explicit value to the interm enum, ideally some really large numbers so that it doesn't collide with any vanilla values # modify interm method (<code>GetSlugStatsNameInterm</code> in the example) to return an int and return original value as int when EE is not installed # instead of switching over <syntaxhighlight lang="charp"> //... //... </syntaxhighlight> --> === Manual extension === ''Using this feature requires referencing EE assembly in your project.'' This method is useful when you don't know what name your new entries will have to have. It is more cumbersome to use and less safe, but # Ensure that EE has been initialized. You can either wait until the <code>EnumExt_</code> get appropriate values, or call <code>PastebinMachine.EnumExtender.EnsureInit()</code> # Call <code>PastebinMachine.EnumExtender.AddDeclaration(Type, string)</code> one or more times. First parameter is <code>Type</code> of the enum, second is the name of new entry. '''Ensuring there are no name collisions is on you!''' # Call <code>PastebinMachine.EnumExtender.ExtendEnumsAgain</code> ''once'' to register all your new enums. '''NOTE''': Last step may have a noticeable overhead, and each call to <code>ExtendEnumsAgain</code> causes a small but permanent memory leak. Do not overuse. <code>ExtendEnumsAgain</code> does not return the added values, you have to obtain them manually through <code>Enum.GetNames()</code> or <code>Enum.GetValues()</code>. Storing the resulting values correctly is the user's responsibility. == Summary == Both modes allow you to use methods like <code>Enum.Parse</code> with extended values freely. RW codebase uses enums pretty much everywhere, so EnumExtender is a often a vital dependency. [[Category:Code Mods]] afc2f77ed47a0ce8dc325860eea3e163e3ca5ea9 Main Page 0 1 106 96 2022-08-05T17:56:14Z Cashewww 2 /* Where to Start... */ wikitext text/x-wiki __NOTOC__ [[File:RWModdingTitle.png|800px|frameless|center]] <br> <div id="intro-text" style="text-align: center;"> '''Welcome!''' The Rain World Modding Wiki is a place to share information about modding the video game, ''Rain World''. For more about the game, check out the '''[https://rainworld.miraheze.org/wiki/Rain_World_Wiki Official Rain World Wiki]'''! This wiki is currently in the process of being ported from an old wiki. To get involved, be sure to check out the modding category in the [https://discord.gg/rainworld Rain World Discord]. </div> == Where to Start... == For instructions for installing mods, see [[Installing Mods]]. On a technical level, mods can be split into the following families: * [[Categories:Code Mods|Code Mods]] (any mod where the main component is a .dll file) * [[Categories:Content Mods|Content Mods]] (this includes region packs, arenas, etc.). Follow one of the links above to learn more about making these kinds of mods. Sometimes there is overlap. For example a [[Custom Region Support|region pack]] (a type of content mod) may require additional code mods for custom creatures, or a code mod may require additional asset files (though often they are embedded within the dll). If have questions that the wiki can't yet answer, feel free to ask in the modding category in the [https://discord.gg/rainworld Rain World Discord]. f7d10ed023345f5c3bbd31798af952a9c41db096 109 106 2022-08-05T18:08:45Z Cashewww 2 fix mod type category links wikitext text/x-wiki __NOTOC__ [[File:RWModdingTitle.png|800px|frameless|center]] <br> <div id="intro-text" style="text-align: center;"> '''Welcome!''' The Rain World Modding Wiki is a place to share information about modding the video game, ''Rain World''. For more about the game, check out the '''[https://rainworld.miraheze.org/wiki/Rain_World_Wiki Official Rain World Wiki]'''! This wiki is currently in the process of being ported from an old wiki. To get involved, be sure to check out the modding category in the [https://discord.gg/rainworld Rain World Discord]. </div> == Where to Start... == For instructions for installing mods, see [[Installing Mods]]. On a technical level, mods can be split into the following families: * [[:Category:Code Mods|Code Mods]] (any mod where the main component is a .dll file) * [[:Category:Content Mods|Content Mods]] (this includes region packs, arenas, etc.). Follow one of the links above to learn more about making these kinds of mods. Sometimes there is overlap. For example a [[Custom Region Support|region pack]] (a type of content mod) may require additional code mods for custom creatures, or a code mod may require additional asset files (though often they are embedded within the dll). If you have questions that the wiki can't yet answer, feel free to ask in the modding category in the [https://discord.gg/rainworld Rain World Discord]. If you have modding knowledge that the wiki doesn't yet have, please do contribute! 633a101cdd4f3e8fddca9495df0dbc19ace91c28 BepInPlugins 0 95 107 2022-08-05T18:01:30Z Thalber 3 Created page with "BepInPlugins are a kind of game mod native to [[BepInEx]]. They are not compatible with Partiality. They should be placed in <code>Rain World/BepInEx/plugins</code>. == Creating a BepInPlugin == === Prerequisites === * A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary) * Rain World with RW BepInEx set up - see [[BepInEx|here]]. * Some kind of .NET programming environment, probably Visual Studio if you're..." wikitext text/x-wiki BepInPlugins are a kind of game mod native to [[BepInEx]]. They are not compatible with Partiality. They should be placed in <code>Rain World/BepInEx/plugins</code>. == Creating a BepInPlugin == === Prerequisites === * A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary) * Rain World with RW BepInEx set up - see [[BepInEx|here]]. * Some kind of .NET programming environment, probably Visual Studio if you're on Windows, or Visual Studio Code for Linux/Mac. The guide below will assume you're already comfortable with the first prerequisite and your editor and environment of choice. ** The .NET Development pack for Visual Studio (or similar for other environments - you need to be able to use .NET Framework 3.5) === Step 1 - The project === Create a new C# .NET Framework 3.5 Class Library project in your IDE. You will then need to [add some references](<nowiki>https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019</nowiki>). It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/plugins/PartialityWrapper/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/core/BepInEx.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/Assembly-CSharp.dll</code> - note: you will need to modify this before accessing private members; see the section "Replacement of Publicity Stunt" on [[BepInEx]] page. === Step 2 - The BepInPlugin class === In a your new C# file, make a public class that has the <code>BepInEx.BepInPlugin</code> attribute and inherits from <code>BepInEx.BaseUnityPlugin</code> . The <code>BaseUnityPlugin</code> class inherits from <code>MonoBehaviour</code>, so you can use standard Unity script methods such as <code>OnEnable</code> and <code>OnDisable</code> in this class.<syntaxhighlight lang="csharp"> using BepInEx; namespace SomeMod {     [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] // (GUID, mod name, mod version)     public class MyModName : BaseUnityPlugin     {     } } </syntaxhighlight> === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example:<syntaxhighlight lang="csharp"> [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] public class MyMod : BaseUnityPlugin {     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         /* This method will be subscribed to Player.Update. */         orig(self, eu);         /* Calling orig is what allows the original method and          * other hooks to the same method do their thing.          * Not calling this is almost always undesirable, and          * can cause big issues.          *   You can execute code before or after the call of          * orig as necessary.          */     } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote>Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and copy the mod's DLL file from wherever your build output is to <code>Rain World/BepInEx/plugins/</code> and run Rain World. ddd81fcacf01c70f7cbbe0c12dbd85342865d803 110 107 2022-08-05T18:13:21Z Thalber 3 wikitext text/x-wiki BepInPlugins are a kind of game mod native to [[BepInEx]]. They are not compatible with Partiality. They should be placed in <code>Rain World/BepInEx/plugins</code>. == Creating a BepInPlugin == === Prerequisites === * A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary) * Rain World with RW BepInEx set up - see [[BepInEx|here]]. * Some kind of .NET programming environment, probably Visual Studio if you're on Windows, or Visual Studio Code for Linux/Mac. The guide below will assume you're already comfortable with the first prerequisite and your editor and environment of choice. ** The .NET Development pack for Visual Studio (or similar for other environments - you need to be able to use .NET Framework 3.5) === Step 1 - The project === Create a new C# .NET Framework 3.5 Class Library project in your IDE. You will then need to [add some references](<nowiki>https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019</nowiki>). It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/plugins/PartialityWrapper/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/core/BepInEx.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/Assembly-CSharp.dll</code> - note: you will need to modify this before accessing private members; see the section "Replacement of Publicity Stunt" on [[BepInEx]] page. === Step 2 - The BepInPlugin class === In a your new C# file, make a public class that has the <code>BepInEx.BepInPlugin</code> attribute and inherits from <code>BepInEx.BaseUnityPlugin</code> . The <code>BaseUnityPlugin</code> class inherits from <code>MonoBehaviour</code>, so you can use standard Unity script methods such as <code>OnEnable</code> and <code>OnDisable</code> in this class.<syntaxhighlight lang="csharp"> using BepInEx; namespace SomeMod {     [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] // (GUID, mod name, mod version)     public class MyModName : BaseUnityPlugin     {     } } </syntaxhighlight> === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example:<syntaxhighlight lang="csharp"> [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] public class MyMod : BaseUnityPlugin {     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         /* This method will be subscribed to Player.Update. */         orig(self, eu);         /* Calling orig is what allows the original method and          * other hooks to the same method do their thing.          * Not calling this is almost always undesirable, and          * can cause big issues.          *   You can execute code before or after the call of          * orig as necessary.          */     } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote>Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and copy the mod's DLL file from wherever your build output is to <code>Rain World/BepInEx/plugins/</code> and run Rain World. [[Category:Code Mods]] f07fc776830a47921a69acca61c718221044fb59 114 110 2022-08-05T18:47:59Z Thalber 3 /* Creating a BepInPlugin */ wikitext text/x-wiki BepInPlugins are a kind of game mod native to [[BepInEx]]. They are not compatible with Partiality. They should be placed in <code>Rain World/BepInEx/plugins</code>. == Creating a BepInPlugin == === Prerequisites === * A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary) * Rain World with RW BepInEx set up - see [[BepInEx|here]]. * Some kind of .NET programming environment, probably Visual Studio if you're on Windows, or Visual Studio Code for Linux/Mac. The guide below will assume you're already comfortable with the first prerequisite and your editor and environment of choice. ** The .NET Development pack for Visual Studio (or similar for other environments - you need to be able to use .NET Framework 3.5) === Step 1 - The project === Create a new C# .NET Framework 3.5 Class Library project in your IDE. You will then need to [https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019 add some references]. It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/plugins/PartialityWrapper/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/core/BepInEx.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/Assembly-CSharp.dll</code> - note: you will need to modify this before accessing private members; see the section "Replacement of Publicity Stunt" on [[BepInEx]] page. === Step 2 - The BepInPlugin class === In a your new C# file, make a public class that has the <code>BepInEx.BepInPlugin</code> attribute and inherits from <code>BepInEx.BaseUnityPlugin</code> . The <code>BaseUnityPlugin</code> class inherits from <code>MonoBehaviour</code>, so you can use standard Unity script methods such as <code>OnEnable</code> and <code>OnDisable</code> in this class.<syntaxhighlight lang="csharp"> using BepInEx; namespace SomeMod {     [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] // (GUID, mod name, mod version)     public class MyModName : BaseUnityPlugin     {     } } </syntaxhighlight> === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example:<syntaxhighlight lang="csharp"> [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] public class MyMod : BaseUnityPlugin {     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         /* This method will be subscribed to Player.Update. */         orig(self, eu);         /* Calling orig is what allows the original method and          * other hooks to the same method do their thing.          * Not calling this is almost always undesirable, and          * can cause big issues.          *   You can execute code before or after the call of          * orig as necessary.          */     } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote>Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and copy the mod's DLL file from wherever your build output is to <code>Rain World/BepInEx/plugins/</code> and run Rain World. [[Category:Code Mods]] 6b51b305db7d7c5e1306199cc62483254200ba09 124 114 2022-08-05T22:29:07Z Cashewww 2 add advanced techniques wikitext text/x-wiki BepInPlugins are a kind of game mod native to [[BepInEx]]. They are not compatible with Partiality. They should be placed in <code>Rain World/BepInEx/plugins</code>. == Creating a BepInPlugin == === Prerequisites === * A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary) * Rain World with RW BepInEx set up - see [[BepInEx|here]]. * Some kind of .NET programming environment, probably Visual Studio if you're on Windows, or Visual Studio Code for Linux/Mac. The guide below will assume you're already comfortable with the first prerequisite and your editor and environment of choice. ** The .NET Development pack for Visual Studio (or similar for other environments - you need to be able to use .NET Framework 3.5) === Step 1 - The project === Create a new C# .NET Framework 3.5 Class Library project in your IDE. You will then need to [https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019 add some references]. It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/plugins/PartialityWrapper/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/core/BepInEx.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/Assembly-CSharp.dll</code> - note: you will need to modify this before accessing private members; see the section "Replacement of Publicity Stunt" on [[BepInEx]] page. === Step 2 - The BepInPlugin class === In a your new C# file, make a public class that has the <code>BepInEx.BepInPlugin</code> attribute and inherits from <code>BepInEx.BaseUnityPlugin</code> . The <code>BaseUnityPlugin</code> class inherits from <code>MonoBehaviour</code>, so you can use standard Unity script methods such as <code>OnEnable</code> and <code>OnDisable</code> in this class.<syntaxhighlight lang="csharp"> using BepInEx; namespace SomeMod {     [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] // (GUID, mod name, mod version)     public class MyModName : BaseUnityPlugin     {     } } </syntaxhighlight> === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example:<syntaxhighlight lang="csharp"> [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] public class MyMod : BaseUnityPlugin {     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         /* This method will be subscribed to Player.Update. */         orig(self, eu);         /* Calling orig is what allows the original method and          * other hooks to the same method do their thing.          * Not calling this is almost always undesirable, and          * can cause big issues.          *   You can execute code before or after the call of          * orig as necessary.          */     } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote>Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and copy the mod's DLL file from wherever your build output is to <code>Rain World/BepInEx/plugins/</code> and run Rain World. == Advanced Techniques == === IL Hooking === IL hooking can be used to modify the Intermediate Language (IL) instructions of the game at runtime. This allows advanced editing of individual instructions within the game code. Risk of Thunder's guide to IL hooking can be found [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ here]. === RuntimeDetour === RuntimeDetour can be used to hook methods not covered by HOOKS-Assembly-CSharp.dll, as well as property getters and setters (see [[Hooking a Property]]). MonoMod's RuntimeDetour guide can be found [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md here]. === Harmony Patching === Harmony patching is a form of runtime patching. The HarmonyX wiki can be found [https://github.com/BepInEx/HarmonyX/wiki here]. [[Category:Code Mods]] b643ea0ae4031418324a54401f9b11916bdf2f28 125 124 2022-08-05T22:35:09Z Cashewww 2 /* Step 2 - The BepInPlugin class */ wikitext text/x-wiki BepInPlugins are a kind of game mod native to [[BepInEx]]. They are not compatible with Partiality. They should be placed in <code>Rain World/BepInEx/plugins</code>. == Creating a BepInPlugin == === Prerequisites === * A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary) * Rain World with RW BepInEx set up - see [[BepInEx|here]]. * Some kind of .NET programming environment, probably Visual Studio if you're on Windows, or Visual Studio Code for Linux/Mac. The guide below will assume you're already comfortable with the first prerequisite and your editor and environment of choice. ** The .NET Development pack for Visual Studio (or similar for other environments - you need to be able to use .NET Framework 3.5) === Step 1 - The project === Create a new C# .NET Framework 3.5 Class Library project in your IDE. You will then need to [https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019 add some references]. It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/plugins/PartialityWrapper/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/core/BepInEx.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/Assembly-CSharp.dll</code> - note: you will need to modify this before accessing private members; see the section "Replacement of Publicity Stunt" on [[BepInEx]] page. === Step 2 - The BepInPlugin class === In a your new C# file, make a public class that has the <code>BepInEx.BepInPlugin</code> attribute and inherits from <code>BepInEx.BaseUnityPlugin</code> . The <code>BaseUnityPlugin</code> class inherits from <code>MonoBehaviour</code>, so you can use standard Unity script methods such as <code>OnEnable</code> and <code>OnDisable</code> in this class. The GUID should be unique to this plugin: something like "scholar" could be popular, which may result in BepInEx not loading your mod. Usually, people opt for the <code>username[dot]mode_name</code> format. <syntaxhighlight lang="csharp"> using BepInEx; namespace SomeMod {     [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] // (GUID, mod name, mod version)     public class MyModName : BaseUnityPlugin     {     } } </syntaxhighlight> === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example:<syntaxhighlight lang="csharp"> [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] public class MyMod : BaseUnityPlugin {     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         /* This method will be subscribed to Player.Update. */         orig(self, eu);         /* Calling orig is what allows the original method and          * other hooks to the same method do their thing.          * Not calling this is almost always undesirable, and          * can cause big issues.          *   You can execute code before or after the call of          * orig as necessary.          */     } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote>Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and copy the mod's DLL file from wherever your build output is to <code>Rain World/BepInEx/plugins/</code> and run Rain World. == Advanced Techniques == === IL Hooking === IL hooking can be used to modify the Intermediate Language (IL) instructions of the game at runtime. This allows advanced editing of individual instructions within the game code. Risk of Thunder's guide to IL hooking can be found [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ here]. === RuntimeDetour === RuntimeDetour can be used to hook methods not covered by HOOKS-Assembly-CSharp.dll, as well as property getters and setters (see [[Hooking a Property]]). MonoMod's RuntimeDetour guide can be found [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md here]. === Harmony Patching === Harmony patching is a form of runtime patching. The HarmonyX wiki can be found [https://github.com/BepInEx/HarmonyX/wiki here]. [[Category:Code Mods]] 2e9e926323b036bc224c2ef1c8167e876ccda67f 126 125 2022-08-05T22:35:58Z Cashewww 2 [dot] -> . wikitext text/x-wiki BepInPlugins are a kind of game mod native to [[BepInEx]]. They are not compatible with Partiality. They should be placed in <code>Rain World/BepInEx/plugins</code>. == Creating a BepInPlugin == === Prerequisites === * A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary) * Rain World with RW BepInEx set up - see [[BepInEx|here]]. * Some kind of .NET programming environment, probably Visual Studio if you're on Windows, or Visual Studio Code for Linux/Mac. The guide below will assume you're already comfortable with the first prerequisite and your editor and environment of choice. ** The .NET Development pack for Visual Studio (or similar for other environments - you need to be able to use .NET Framework 3.5) === Step 1 - The project === Create a new C# .NET Framework 3.5 Class Library project in your IDE. You will then need to [https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019 add some references]. It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/plugins/PartialityWrapper/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/core/BepInEx.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/Assembly-CSharp.dll</code> - note: you will need to modify this before accessing private members; see the section "Replacement of Publicity Stunt" on [[BepInEx]] page. === Step 2 - The BepInPlugin class === In a your new C# file, make a public class that has the <code>BepInEx.BepInPlugin</code> attribute and inherits from <code>BepInEx.BaseUnityPlugin</code> . The <code>BaseUnityPlugin</code> class inherits from <code>MonoBehaviour</code>, so you can use standard Unity script methods such as <code>OnEnable</code> and <code>OnDisable</code> in this class. The GUID should be unique to this plugin: something like "scholar" could be popular, which may result in BepInEx not loading your mod. Usually, people opt for the <code>username.mode_name</code> format. <syntaxhighlight lang="csharp"> using BepInEx; namespace SomeMod {     [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] // (GUID, mod name, mod version)     public class MyModName : BaseUnityPlugin     {     } } </syntaxhighlight> === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example:<syntaxhighlight lang="csharp"> [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] public class MyMod : BaseUnityPlugin {     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         /* This method will be subscribed to Player.Update. */         orig(self, eu);         /* Calling orig is what allows the original method and          * other hooks to the same method do their thing.          * Not calling this is almost always undesirable, and          * can cause big issues.          *   You can execute code before or after the call of          * orig as necessary.          */     } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote>Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and copy the mod's DLL file from wherever your build output is to <code>Rain World/BepInEx/plugins/</code> and run Rain World. == Advanced Techniques == === IL Hooking === IL hooking can be used to modify the Intermediate Language (IL) instructions of the game at runtime. This allows advanced editing of individual instructions within the game code. Risk of Thunder's guide to IL hooking can be found [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ here]. === RuntimeDetour === RuntimeDetour can be used to hook methods not covered by HOOKS-Assembly-CSharp.dll, as well as property getters and setters (see [[Hooking a Property]]). MonoMod's RuntimeDetour guide can be found [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md here]. === Harmony Patching === Harmony patching is a form of runtime patching. The HarmonyX wiki can be found [https://github.com/BepInEx/HarmonyX/wiki here]. [[Category:Code Mods]] e1ede3d8d6b90f8ccfcaf6fd6d7007e790afafb1 149 126 2022-08-07T13:47:18Z Cashewww 2 mention enumextender wikitext text/x-wiki BepInPlugins are a kind of game mod native to [[BepInEx]]. They are not compatible with Partiality. They should be placed in <code>Rain World/BepInEx/plugins</code>. == Creating a BepInPlugin == === Prerequisites === * A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary) * Rain World with RW BepInEx set up - see [[BepInEx|here]]. * Some kind of .NET programming environment, probably Visual Studio if you're on Windows, or Visual Studio Code for Linux/Mac. The guide below will assume you're already comfortable with the first prerequisite and your editor and environment of choice. ** The .NET Development pack for Visual Studio (or similar for other environments - you need to be able to use .NET Framework 3.5) === Step 1 - The project === Create a new C# .NET Framework 3.5 Class Library project in your IDE. You will then need to [https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019 add some references]. It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/plugins/PartialityWrapper/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/core/BepInEx.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/Assembly-CSharp.dll</code> - note: you will need to modify this before accessing private members; see the section "Replacement of Publicity Stunt" on [[BepInEx]] page. === Step 2 - The BepInPlugin class === In a your new C# file, make a public class that has the <code>BepInEx.BepInPlugin</code> attribute and inherits from <code>BepInEx.BaseUnityPlugin</code> . The <code>BaseUnityPlugin</code> class inherits from <code>MonoBehaviour</code>, so you can use standard Unity script methods such as <code>OnEnable</code> and <code>OnDisable</code> in this class. The GUID should be unique to this plugin: something like "scholar" could be popular, which may result in BepInEx not loading your mod. Usually, people opt for the <code>username.mode_name</code> format. <syntaxhighlight lang="csharp"> using BepInEx; namespace SomeMod {     [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] // (GUID, mod name, mod version)     public class MyModName : BaseUnityPlugin     {     } } </syntaxhighlight> === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example:<syntaxhighlight lang="csharp"> [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] public class MyMod : BaseUnityPlugin {     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         /* This method will be subscribed to Player.Update. */         orig(self, eu);         /* Calling orig is what allows the original method and          * other hooks to the same method do their thing.          * Not calling this is almost always undesirable, and          * can cause big issues.          *   You can execute code before or after the call of          * orig as necessary.          */     } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote>Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and copy the mod's DLL file from wherever your build output is to <code>Rain World/BepInEx/plugins/</code> and run Rain World. == Enums == Due to their abundance in Rain World's code and their general usefulness in state machines, it's very possible that at some point you'll want to add your own value to an enum. To do that, you can use [[EnumExtender]]. == Advanced Techniques == === IL Hooking === IL hooking can be used to modify the Intermediate Language (IL) instructions of the game at runtime. This allows advanced editing of individual instructions within the game code. Risk of Thunder's guide to IL hooking can be found [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ here]. === RuntimeDetour === RuntimeDetour can be used to hook methods not covered by HOOKS-Assembly-CSharp.dll, as well as property getters and setters (see [[Hooking a Property]]). MonoMod's RuntimeDetour guide can be found [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md here]. === Harmony Patching === Harmony patching is a form of runtime patching. The HarmonyX wiki can be found [https://github.com/BepInEx/HarmonyX/wiki here]. [[Category:Code Mods]] e4c40d25654415d86f0d0473b86d7ba7164bf099 Category:Code Mods 14 74 108 77 2022-08-05T18:06:55Z Cashewww 2 Cashewww moved page [[Categories:Code Mods]] to [[Category:Code Mods]] without leaving a redirect wikitext text/x-wiki Code mods are incredibly versatile. They allow for fixing bugs in the vanilla game, adding quality of life (QoL) features, and all sorts of brand new features including new creatures and gamemodes. Code mods are sometimes included in Region Packs, either as supplimentary features or dependencies of those features. de14b28b0aa6946dedbb65ddec3c34ffb66cf4dd 123 108 2022-08-05T22:18:49Z Cashewww 2 wikitext text/x-wiki Code mods are incredibly versatile. They allow for fixing bugs in the vanilla game, adding quality of life (QoL) features, and all sorts of brand new features including new creatures and gamemodes. Code mods are sometimes included in Region Packs, either as supplimentary features or dependencies of those features. To load code mods, we use a modified version of [[BepInEx]]. == Writing Code Mods == Rain World is programmed in C# with Unity, meaning that we have access to plenty of .NET and Unity oriented modding tools. RW code mods are generally written in C# and built for the .NET Framework 3.5 runtime. If you're looking to start making code mods, it's recommended that you start with [[BepInPlugins]]. You're likely to get the most support with these, they're the easiest to make, and they're very capable. Modern Rain World code mods typically come in a few flavours... * [[BepInPlugins]] - ''the most common. They largely use a technique called hooking, which allows for many possibilities and makes for good compatibility with other mods.'' * [https://docs.bepinex.dev/articles/dev_guide/preloader_patchers.html Preloader Patchers] - ''powered by Mono.Cecil. Used to apply changes to asseblies during the preloader phase.'' Older Rain World code mods are generally: * [[Standalone Mods]] * [[Partiality Mods]] * [[MonoMod Patches]] 8976ff0e321821e89f27d30f6ec3032917c5f39d Category:Content Mods 14 96 115 2022-08-05T18:54:53Z Cashewww 2 created content mods page wikitext text/x-wiki {{Cleanup}} Content mods are mods that are primarily asset files (e.g. images, text/config files, audio). 6de9eca371bc3dc8c226410429a364540f1758a4 134 115 2022-08-06T12:49:30Z Thalber 3 wikitext text/x-wiki {{Cleanup}} Content mods are mods that consist primarily of asset files (e.g. sprite sheets, room files, audio etc). Content mods may contain new regions, sprite packs for player characters, arena level packs and so on. Content mods may depend on code mods in order to be loaded (such as [[CRS]]). They may be redistributed with supporting code libraries for additional features. 6b891e4830f8bebb59c26bac343ed5df8d693ada File:BepInEx Installation.png 6 97 127 2022-08-05T23:04:18Z Cashewww 2 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 BepInEx 0 98 128 2022-08-05T23:23:44Z Cashewww 2 started porting from gh wikitext text/x-wiki BepInEx is a mod loader and plugin framework primarily for Unity and XNA games. '''It is important to note''' that the generic BepInEx releases are not directly compatible with Partiality Mods, which make up a large portion of mods for Rain World v1.5. Currently, it is imperative you use a specially modified version of BepInEx to use the majority of existing Rain World mods. There are two ways of getting an appropriate version of BepInEx. '''Either''' use the [[BepInEx#Installation|Installation]] section to install RW BepInEx '''OR''' download [https://github.com/Dual-Iron/RwModLoader#readme Realm]. Realm has an in-game mod management interface, but is currently incompatible with a small number of mods. == Installation == ''Tip: If you got the game from Steam then the default location for the Rain World folder is <code>C:\Program Files (x86)\Steam\steamapps\common\Rain World</code>, but this will be different if you changed the installation settings.'' All of the steps below for installing RW BepInEx and BOI (an app that helps manage mod files) are presented in [https://youtu.be/brDN_8uN6-U this video]. [[File:BepInEx Installation.png|alt=The BepInEx folder, doorstep_config.ini, and winhttp.dll should be in the Rain World folder. |thumb|474x474px|This is what the Rain World folder should look like after installing BepInEx. ]] If you have not installed Partiality for the current installation of Rain World, skip to step 2. # Go to the <code>Rain World/RainWorld_Data</code> folder, delete the folder called <code>Managed</code>, and rename <code>Managed_backup</code> to <code>Managed</code>. # [https://beestuff.pythonanywhere.com/audb/api/v2/bepinex/download Download RW BepInEx]. # Extract the contents of the .zip archive and copy its ''contents'' to the Rain World folder. # At this point, your Rain World folder should look like the image on the right. You can also check the installation by running the game as you normally would - if a file called LogOutput.log is now in the BepInEx folder, then BepInEx is starting up. == Using Mods == === Option 1: BOI === BOI is a graphical application for mod management with RW BepInEx. It also includes a few other tools such as save file management and ability to change [[Dev Tools]] settings. It can be installed from [https://github.com/Rain-World-Modding/BOI/releases here] - download the first .zip and extract its contents anywhere (though preferably not inside the Rain World folder). === Option 2: Moving Files === TODO 1e39bb0028c3863a7bf794c1d0a50de197bae1a4 130 128 2022-08-06T10:30:02Z Cashewww 2 fixed anchor link wikitext text/x-wiki BepInEx is a mod loader and plugin framework primarily for Unity and XNA games. '''It is important to note''' that the generic BepInEx releases are not directly compatible with Partiality Mods, which make up a large portion of mods for Rain World v1.5. Currently, it is imperative you use a specially modified version of BepInEx to use the majority of existing Rain World mods. There are two ways of getting an appropriate version of BepInEx. '''Either''' use the [[#Installation|Installation]] section to install RW BepInEx '''OR''' download [https://github.com/Dual-Iron/RwModLoader#readme Realm]. Realm has an in-game mod management interface, but is currently incompatible with a small number of mods. == Installation == ''Tip: If you got the game from Steam then the default location for the Rain World folder is <code>C:\Program Files (x86)\Steam\steamapps\common\Rain World</code>, but this will be different if you changed the installation settings.'' All of the steps below for installing RW BepInEx and BOI (an app that helps manage mod files) are presented in [https://youtu.be/brDN_8uN6-U this video]. [[File:BepInEx Installation.png|alt=The BepInEx folder, doorstep_config.ini, and winhttp.dll should be in the Rain World folder. |thumb|474x474px|This is what the Rain World folder should look like after installing BepInEx. ]] If you have not installed Partiality for the current installation of Rain World, skip to step 2. # Go to the <code>Rain World/RainWorld_Data</code> folder, delete the folder called <code>Managed</code>, and rename <code>Managed_backup</code> to <code>Managed</code>. # [https://beestuff.pythonanywhere.com/audb/api/v2/bepinex/download Download RW BepInEx]. # Extract the contents of the .zip archive and copy its ''contents'' to the Rain World folder. # At this point, your Rain World folder should look like the image on the right. You can also check the installation by running the game as you normally would - if a file called LogOutput.log is now in the BepInEx folder, then BepInEx is starting up. == Using Mods == === Option 1: BOI === BOI is a graphical application for mod management with RW BepInEx. It also includes a few other tools such as save file management and ability to change [[Dev Tools]] settings. It can be installed from [https://github.com/Rain-World-Modding/BOI/releases here] - download the first .zip and extract its contents anywhere (though preferably not inside the Rain World folder). === Option 2: Moving Files === TODO ab000bcaec6c247283e81ad03fdc9e36da18deb0 131 130 2022-08-06T10:35:58Z Cashewww 2 added manual bep usage wikitext text/x-wiki BepInEx is a mod loader and plugin framework primarily for Unity and XNA games. '''It is important to note''' that the generic BepInEx releases are not directly compatible with Partiality Mods, which make up a large portion of mods for Rain World v1.5. Currently, it is imperative you use a specially modified version of BepInEx to use the majority of existing Rain World mods. There are two ways of getting an appropriate version of BepInEx. '''Either''' use the [[#Installation|Installation]] section to install RW BepInEx '''OR''' download [https://github.com/Dual-Iron/RwModLoader#readme Realm]. Realm has an in-game mod management interface, but is currently incompatible with a small number of mods. == Installation == ''Tip: If you got the game from Steam then the default location for the Rain World folder is <code>C:\Program Files (x86)\Steam\steamapps\common\Rain World</code>, but this will be different if you changed the installation settings.'' All of the steps below for installing RW BepInEx and BOI (an app that helps manage mod files) are presented in [https://youtu.be/brDN_8uN6-U this video]. [[File:BepInEx Installation.png|alt=The BepInEx folder, doorstep_config.ini, and winhttp.dll should be in the Rain World folder. |thumb|474x474px|This is what the Rain World folder should look like after installing BepInEx. ]] If you have not installed Partiality for the current installation of Rain World, skip to step 2. # Go to the <code>Rain World/RainWorld_Data</code> folder, delete the folder called <code>Managed</code>, and rename <code>Managed_backup</code> to <code>Managed</code>. # [https://beestuff.pythonanywhere.com/audb/api/v2/bepinex/download Download RW BepInEx]. # Extract the contents of the .zip archive and copy its ''contents'' to the Rain World folder. # At this point, your Rain World folder should look like the image on the right. You can also check the installation by running the game as you normally would - if a file called LogOutput.log is now in the BepInEx folder, then BepInEx is starting up. == Using Mods == === Option 1: BOI === BOI is a graphical application for mod management with RW BepInEx. It also includes a few other tools such as save file management and ability to change [[Dev Tools]] settings. It can be installed from [https://github.com/Rain-World-Modding/BOI/releases here] - download the first .zip and extract its contents anywhere (though preferably not inside the Rain World folder). === Option 2: Moving Files === * [[BepInPlugins]] and [[Partiality Mods]] must go in <code>BepInEx/plugins</code> * [[MonoMod Patches]] must be renamed to the format <code>Assembly-CSharp.[mod name].mm.dll</code> and must go in <code>BepInEx/monomod</code> * Preloader patchers must go in <code>BepInEx/patchers</code> 30ff600805ab5e531acb9bdb6ba42c351fc5f90d 132 131 2022-08-06T10:44:04Z Cashewww 2 added linux and realm info wikitext text/x-wiki BepInEx is a mod loader and plugin framework primarily for Unity and XNA games. '''It is important to note''' that the generic BepInEx releases are not directly compatible with Partiality Mods, which make up a large portion of mods for Rain World v1.5. Currently, it is imperative you use a specially modified version of BepInEx to use the majority of existing Rain World mods. '''Another note for Linux/Steam Deck users:''' as Rain World is not natively available for Linux (and Steam Deck is powered by Linux), extra steps are required for installation. [https://gist.github.com/PJB3005/a7b635f171bd34f18a28885afa8f6e8e This guide] will help you set up Realm (a package which includes BepInEx) for Rain World on your Linux device with the help of Steam Proton/WINE. There are two ways of getting an appropriate version of BepInEx. '''Either''' use the [[#Installation|Installation]] section to install RW BepInEx '''OR''' download [https://github.com/Dual-Iron/RwModLoader#readme Realm]. Realm has an in-game mod management interface, but is currently incompatible with a small number of mods. == Installation == ''Tip: If you got the game from Steam then the default location for the Rain World folder is <code>C:\Program Files (x86)\Steam\steamapps\common\Rain World</code>, but this will be different if you changed the installation settings.'' All of the steps below for installing RW BepInEx and BOI (an app that helps manage mod files) are presented in [https://youtu.be/brDN_8uN6-U this video]. [[File:BepInEx Installation.png|alt=The BepInEx folder, doorstep_config.ini, and winhttp.dll should be in the Rain World folder. |thumb|474x474px|This is what the Rain World folder should look like after installing BepInEx. ]] If you have not installed Partiality for the current installation of Rain World, skip to step 2. # Go to the <code>Rain World/RainWorld_Data</code> folder, delete the folder called <code>Managed</code>, and rename <code>Managed_backup</code> to <code>Managed</code>. # [https://beestuff.pythonanywhere.com/audb/api/v2/bepinex/download Download RW BepInEx]. # Extract the contents of the .zip archive and copy its ''contents'' to the Rain World folder. # At this point, your Rain World folder should look like the image on the right. You can also check the installation by running the game as you normally would - if a file called LogOutput.log is now in the BepInEx folder, then BepInEx is starting up. == Using Mods == === Option 1: BOI === BOI is a graphical application for mod management with RW BepInEx. It also includes a few other tools such as save file management and ability to change [[Dev Tools]] settings. It can be installed from [https://github.com/Rain-World-Modding/BOI/releases here] - download the first .zip and extract its contents anywhere (though preferably not inside the Rain World folder). === Option 2: Realm === Realm is a package that includes BepInEx and an in-game mod management interface. It allows for download, installation, and reloading of many mods in-game. See [https://github.com/Dual-Iron/RwModLoader#readme the Realm readme] for more information. === Option 3: Moving Files === * [[BepInPlugins]] and [[Partiality Mods]] must go in <code>BepInEx/plugins</code> * [[MonoMod Patches]] must be renamed to the format <code>Assembly-CSharp.[mod name].mm.dll</code> and must go in <code>BepInEx/monomod</code> * Preloader patchers must go in <code>BepInEx/patchers</code> 40ba8b69f02b4268f79cf96b6966f640cd9156ce 135 132 2022-08-06T12:54:11Z Thalber 3 /* Option 3: Moving Files */ wikitext text/x-wiki BepInEx is a mod loader and plugin framework primarily for Unity and XNA games. '''It is important to note''' that the generic BepInEx releases are not directly compatible with Partiality Mods, which make up a large portion of mods for Rain World v1.5. Currently, it is imperative you use a specially modified version of BepInEx to use the majority of existing Rain World mods. '''Another note for Linux/Steam Deck users:''' as Rain World is not natively available for Linux (and Steam Deck is powered by Linux), extra steps are required for installation. [https://gist.github.com/PJB3005/a7b635f171bd34f18a28885afa8f6e8e This guide] will help you set up Realm (a package which includes BepInEx) for Rain World on your Linux device with the help of Steam Proton/WINE. There are two ways of getting an appropriate version of BepInEx. '''Either''' use the [[#Installation|Installation]] section to install RW BepInEx '''OR''' download [https://github.com/Dual-Iron/RwModLoader#readme Realm]. Realm has an in-game mod management interface, but is currently incompatible with a small number of mods. == Installation == ''Tip: If you got the game from Steam then the default location for the Rain World folder is <code>C:\Program Files (x86)\Steam\steamapps\common\Rain World</code>, but this will be different if you changed the installation settings.'' All of the steps below for installing RW BepInEx and BOI (an app that helps manage mod files) are presented in [https://youtu.be/brDN_8uN6-U this video]. [[File:BepInEx Installation.png|alt=The BepInEx folder, doorstep_config.ini, and winhttp.dll should be in the Rain World folder. |thumb|474x474px|This is what the Rain World folder should look like after installing BepInEx. ]] If you have not installed Partiality for the current installation of Rain World, skip to step 2. # Go to the <code>Rain World/RainWorld_Data</code> folder, delete the folder called <code>Managed</code>, and rename <code>Managed_backup</code> to <code>Managed</code>. # [https://beestuff.pythonanywhere.com/audb/api/v2/bepinex/download Download RW BepInEx]. # Extract the contents of the .zip archive and copy its ''contents'' to the Rain World folder. # At this point, your Rain World folder should look like the image on the right. You can also check the installation by running the game as you normally would - if a file called LogOutput.log is now in the BepInEx folder, then BepInEx is starting up. == Using Mods == === Option 1: BOI === BOI is a graphical application for mod management with RW BepInEx. It also includes a few other tools such as save file management and ability to change [[Dev Tools]] settings. It can be installed from [https://github.com/Rain-World-Modding/BOI/releases here] - download the first .zip and extract its contents anywhere (though preferably not inside the Rain World folder). === Option 2: Realm === Realm is a package that includes BepInEx and an in-game mod management interface. It allows for download, installation, and reloading of many mods in-game. See [https://github.com/Dual-Iron/RwModLoader#readme the Realm readme] for more information. === Option 3: Moving Files === * [[BepInPlugins]] and [[Partiality|Partiality Mods]] must go in <code>BepInEx/plugins</code> * [[MonoMod Patches]] must be renamed to the format <code>Assembly-CSharp.[mod name].mm.dll</code> and must go in <code>BepInEx/monomod</code> * Preloader patchers must go in <code>BepInEx/patchers</code> 47ff0b02e5496358606a3fb7325c20abd8a95966 Partiality 0 99 133 2022-08-06T12:40:42Z Thalber 3 Port Casheww's PL page wikitext text/x-wiki '''Important''' - Partiality is abandoned. Instead, you should use [[BepInEx]]. <br/> Partiality loader was the primary mod loader used for Rain World modding for some years. Partiality loader is no longer maintained, so the mod loader of choice for Rain World is now [[BepInEx]]. The versions of BepInEx used by the Rain World modding community support the usage of Partiality mods. The authority for Rain World Partiality mods is [https://drive.google.com/file/d/1eZE6EVwslhnSIFffmoUxDgUCRTAvD-zP/view Topicular’s Guide to Partiality Modding]. While some aspects are a out of date, many of the concepts relating to the game’s code still apply and are very useful. BepInEx plugins / BepInPlugins are an alternative for Partiality hook mods. For more info, see the [[BepInPlugins]] page. [[Category:Code Mods]] 79a5e04f5e7df016aca441b72510b075685f22a0 Standalone Mods 0 100 136 2022-08-06T13:21:24Z Thalber 3 Created page with "'''Standalone mods''' are the most primitive type of mod, working by directly replacing game files. Standalone mods are distributed as a partial copy of the game and installed by merging that copy into a Rain World installation, replacing all colliding files in the process (including <source lang="" enclose="none">AssemblyCSharp.dll</source>). They are very easy to make but at the same time have some very serious issues, namely with: * '''Compatibility''': If two stand..." wikitext text/x-wiki '''Standalone mods''' are the most primitive type of mod, working by directly replacing game files. Standalone mods are distributed as a partial copy of the game and installed by merging that copy into a Rain World installation, replacing all colliding files in the process (including <source lang="" enclose="none">AssemblyCSharp.dll</source>). They are very easy to make but at the same time have some very serious issues, namely with: * '''Compatibility''': If two standalone mods modify the same file, they're probably terminally incompatible with each other. * '''Ease of removal''': Standalone mods are tedious to uninstall. Steam has "verify integrity of game files" option, which works most of the time; users on most other platform would have to either wipe and reinstall the entire game or keep several installs of RW on disk. * '''Legality''': Standalone mods usually come with modified copy of AssemblyCSharp.dll (typically edited with [[DnSpy]]), which, aside from changes made by the mod, carries the entire rest of vanilla code. This is, strictly speaking, illegal. For these issues, the method is considered obsolete, using it is greatly discouraged. Use [[BepInPlugins|less ancient methods]]] instead. [[Category:Code mods]] [[Category:Content Mods]] f50cb60f4ceaaa077f1c5d680bb38592fb2a9e5f 142 136 2022-08-06T15:40:41Z Cashewww 2 tweaked syntax wikitext text/x-wiki '''Standalone mods''' are the most primitive type of mod, working by directly replacing game files. Standalone mods are distributed as a partial copy of the game and installed by merging that copy into a Rain World installation, replacing all colliding files in the process (including <code>Assembly-CSharp.dll</code>). They are very easy to make but at the same time have some very serious issues, namely with: * '''Compatibility''': If two standalone mods modify the same file, they're probably terminally incompatible with each other. * '''Ease of removal''': Standalone mods are tedious to uninstall. Steam has "verify integrity of game files" option, which works most of the time; users on most other platform would have to either wipe and reinstall the entire game or keep several installs of RW on disk. * '''Legality''': Standalone mods usually come with modified copy of Assembly-CSharp.dll (typically edited with [[DnSpy]]), which, aside from changes made by the mod, carries the entire rest of vanilla code. This is, strictly speaking, illegal. For these issues, the method is considered obsolete, using it is greatly discouraged. Use [[BepInPlugins|less ancient methods]] instead. [[Category:Code mods]] [[Category:Content Mods]] ad44136dd97b6c260674cd6ffbd814b9d81c21d1 143 142 2022-08-06T15:42:42Z Cashewww 2 wikitext text/x-wiki '''Standalone mods''' are the most primitive type of mod, working by directly replacing game files. Standalone mods are distributed as a partial copy of the game and installed by merging that copy into a Rain World installation, replacing all colliding files in the process (including <code>Assembly-CSharp.dll</code>). They are very easy to make but at the same time have some very serious issues, namely with: * '''Compatibility''': If two standalone mods modify the same file, they're probably terminally incompatible with each other. * '''Ease of removal''': Standalone mods are tedious to uninstall. Steam has "verify integrity of game files" option, which works most of the time; users on most other platform would have to either wipe and reinstall the entire game or keep several installs of RW on disk. * '''Legality''': Standalone mods usually come with modified copy of Assembly-CSharp.dll (typically edited with [[DnSpy]]), which, aside from changes made by the mod, carries the entire rest of vanilla code. This is, strictly speaking, illegal. For these issues, the method is considered obsolete, using it is greatly discouraged. Use [[BepInPlugins|less ancient methods]] instead. [[Category:Code Mods]] [[Category:Content Mods]] 90e4508436772955e7c9def3370fd7630e23a5ec Custom Regions Support 0 101 137 2022-08-06T14:41:44Z Thalber 3 Created page with "{{Cleanup}} '''Custom Regions Support''' or '''CRS''' is a library/util mod that was created as an easier way to install [[Content Mods]], replacing file merging. It allows to install multiple region mods at once easily, quickly toggle them, and makes region development less messy. As of now, it is the primary way of installing any and all custom regions, and many of them are ''CRS-exclusive''. Full up-to-date README, source code and CRS-specific technical reference f..." wikitext text/x-wiki {{Cleanup}} '''Custom Regions Support''' or '''CRS''' is a library/util mod that was created as an easier way to install [[Content Mods]], replacing file merging. It allows to install multiple region mods at once easily, quickly toggle them, and makes region development less messy. As of now, it is the primary way of installing any and all custom regions, and many of them are ''CRS-exclusive''. Full up-to-date README, source code and CRS-specific technical reference for modders can be found [[https://github.com/Garrakx/Custom-Regions on its GitHub]]. == Features == === Runtime worldfile merging === ''For basics of region architecture, see [[Architecture of Rain World]]'' CRS attempts to smartly combine region world files and avoid room connectivity conflicts. It is the most effective if region mods don't distribute full modified copies of WORLD_XX.txt files for conflict-prone connection (such as vanilla region's WORLD_XX, when a modded region connects to it), and instead ''only include lines that need to be changed or added''. This is commonly referred to as "refining worldfiles". In addition to connection files, it can also merge region property files. === Region-conditional connections === Connections may be toggled depending on if a certain region is present: <syntaxhighlight lang=""> ROOMS (TM, !BL)roomA : roomB, roomD //only used if TM is installed and BL is not ENDROOMS </syntaxhighlight> This can be combined with unused vanilla behaviour of character-specific connections. === Connection fixer === Starting with v0.9.xx, CRS can attempt to fix some broken connections. This behaviour isn't a catchall but can make some conflicts less lethal. === Additional asset loading === CRS allows easily loading assets commonly bundled with most regions, such as music files, region splash art for passage/regions map screens, decals etc. === Misc === * Making previously hardcoded settings (electric gates, albino colouring on creatures, chance of salamander colouring etc) configurable with json files * Removing creature spawns * No-code addition of custom pearls * Adding unlockable arenas f648549cb35583f36730def20de66c963c63ea07 139 137 2022-08-06T14:45:39Z Thalber 3 wikitext text/x-wiki {{Cleanup}} '''Custom Regions Support''' or '''CRS''' is a library/util mod that was created as an easier way to install [[Content Mods]], replacing file merging. It allows to install multiple region mods at once easily, quickly toggle them, and makes region development less messy. As of now, it is the primary way of installing any and all custom regions, and many of them are ''CRS-exclusive''. Full up-to-date README, source code and CRS-specific technical reference for modders can be found [[https://github.com/Garrakx/Custom-Regions on its GitHub]]. == Features == === Runtime worldfile merging === ''For basics of region architecture, see [[Architecture of Rain World]]'' CRS attempts to smartly combine region world files and avoid room connectivity conflicts. It is the most effective if region mods don't distribute full modified copies of WORLD_XX.txt files for conflict-prone connection (such as vanilla region's WORLD_XX, when a modded region connects to it), and instead ''only include lines that need to be changed or added''. This is commonly referred to as "refining worldfiles". In addition to connection files, it can also merge region property files. === In-game downloader === CRS config menu allows the user to install most region packs from inside the game in one click, including their dependency DLLs, and also quickly toggle installed packs on and off. Downloader menu is reshuffled every day to give every CRS-published region a shot. === Region-conditional connections === Connections may be toggled depending on if a certain region is present: <syntaxhighlight lang=""> ROOMS (TM, !BL)roomA : roomB, roomD //only used if TM is installed and BL is not ENDROOMS </syntaxhighlight> This can be combined with unused vanilla behaviour of character-specific connections. === Connection fixer === Starting with v0.9.xx, CRS can attempt to fix some broken connections. This behaviour isn't a catchall but can make some conflicts less lethal. === Additional asset loading === CRS allows easily loading assets commonly bundled with most regions, such as music files, region splash art for passage/regions map screens, decals etc. === Misc === * Making previously hardcoded settings (electric gates, albino colouring on creatures, chance of salamander colouring etc) configurable with json files * Removing creature spawns * No-code addition of custom pearls * Adding unlockable arenas b46ed5410876f82f01df4b5980465add768e22f9 CRS 0 102 138 2022-08-06T14:43:08Z Thalber 3 Redirected page to [[Custom Regions Support]] wikitext text/x-wiki #REDIRECT [[Custom Regions Support]] baf54d4f91218c46cf22aa2ae14f756b72205994 Content Mods 0 103 140 2022-08-06T14:48:01Z Cashewww 2 Redirected page to [[Category:Content Mods]] wikitext text/x-wiki #REDIRECT [[Category:Content_Mods]] 4e6b088ae8094d6f76901ceeaf1ca8c39b9a5140 Code Mods 0 104 141 2022-08-06T14:54:09Z Cashewww 2 Redirected page to [[Category:Code Mods]] wikitext text/x-wiki #REDIRECT [[Category:Code_Mods]] b26a732c0a09b49333937eca8fd694cacfdb9bc4 Partiality Mods 0 105 145 2022-08-07T12:56:49Z Cashewww 2 Redirected page to [[Partiality]] wikitext text/x-wiki #REDIRECT [[Partiality]] 1209e661aa7a8cf1defa405baf1faf31643b7dd3 Custom Region Support 0 106 146 2022-08-07T13:34:54Z Cashewww 2 Redirected page to [[Custom Regions Support]] wikitext text/x-wiki #REDIRECT [[Custom Regions Support]] baf54d4f91218c46cf22aa2ae14f756b72205994 MonoMod Patches 0 107 147 2022-08-07T13:38:32Z Thalber 3 Created page with "{{Cleanup}} '''MonoModPatches''' or '''MMPatches''' are one of the simplest ways of modifying vanilla code. They can be used with current version of our [[BepInEx]] package. MonoMod's [https://github.com/MonoMod/MonoMod/blob/master/README.md README] contains a description of this method. Short summary and RW-specific aspects are presented below. == Creation == * Create a project referencing both <code>MonoMod.exe</code> and <code>AssemblyCSharp.dll</code> * Create a..." wikitext text/x-wiki {{Cleanup}} '''MonoModPatches''' or '''MMPatches''' are one of the simplest ways of modifying vanilla code. They can be used with current version of our [[BepInEx]] package. MonoMod's [https://github.com/MonoMod/MonoMod/blob/master/README.md README] contains a description of this method. Short summary and RW-specific aspects are presented below. == Creation == * Create a project referencing both <code>MonoMod.exe</code> and <code>AssemblyCSharp.dll</code> * Create a type deriving from target class * Mark your class for patching. This can be done in two ways: *# Place your class in the exact same namespace and name it <code>patch_OriginalNamehere</code> (<code>patch_Player</code> to patch <code>Player</code>) *# Denote your class with <code>MonoModPatch</code> attribute like the following example <!--(<code>Custom</code>)--> <syntaxhighlight lang="csharp"> [MonoModPatch("global::Player")] //"global::" is the namespace for classes appearing "without a namespace" public class CustomPlayer : Player { } </syntaxhighlight> * For every method to patch, use the following pattern: <syntaxhighlight lang="csharp"> [MonoModPatch("global::Player")] public class CustomPlayer : Player { public extern void orig_Update(bool eu); public override void Update(bool eu) { //do your things orig_Update(eu); // original method body is inserted at the site of this call. Omit to not use original code at all (also disables layering MMPatches). //do your things } } </syntaxhighlight> To access a private member, create one with matching signature (type / name / params etc) and denote it with <code>MonoModIgnore</code> attribute. To patch a non-override public method, use <code>new</code> to hide the vanilla method for the compiler. === Things to note === * MMPatches should not be shipped in the same assembly as partmods/[[BepInPlugins]]. If that is done, there is only a small chance doing that will ''not'' turn your game into an firecracker plant. * <code>MonoModRules</code> described in MonoMod readme does not seem to coexist nicely with BepInEx. == Usage == MMPatches have to be named as following: <code>[anything].mm.dll</code>. They are loaded from <code>Rain World/BepInEx/monomod/</code> ''at preloader time''. [[BOI]] renames files automatically in a futile attempt to make the process more intuitive for the end user. 05626d2c86f3a0cb7061a3eb750cc570c9ed87b0 148 147 2022-08-07T13:42:35Z Thalber 3 wikitext text/x-wiki {{Cleanup}} '''MonoModPatches''' or '''MMPatches''' are one of the simplest ways of modifying vanilla code. They can be used with current version of our [[BepInEx]] package. MonoMod's [https://github.com/MonoMod/MonoMod/blob/master/README.md README] contains a description of this method. Short summary and RW-specific aspects are presented below. == Creation == * Create a project referencing both <code>MonoMod.exe</code> and <code>AssemblyCSharp.dll</code> * Create a type deriving from target class * Mark your class for patching. This can be done in two ways: *# Place your class in the exact same namespace and name it <code>patch_OriginalNamehere</code> (<code>patch_Player</code> to patch <code>Player</code>) *# Denote your class with <code>MonoModPatch</code> attribute like the following example <!--(<code>Custom</code>)--> <syntaxhighlight lang="csharp"> [MonoModPatch("global::Player")] //"global::" is the namespace for classes appearing "without a namespace" public class CustomPlayer : Player { } </syntaxhighlight> * For every method to patch, use the following pattern: <syntaxhighlight lang="csharp"> [MonoModPatch("global::Player")] public class CustomPlayer : Player { public extern void orig_Update(bool eu); public override void Update(bool eu) { //do your things orig_Update(eu); // original method body is inserted at the site of this call. Omit to not use original code at all (also disables layering MMPatches). //do your things } } </syntaxhighlight> To access a private member, create one with matching signature (type / name / params etc) and denote it with <code>MonoModIgnore</code> attribute. To patch a non-override public method, use <code>new</code> to hide the vanilla method for the compiler. === Things to note === * MMPatches should not be shipped in the same assembly as partmods/[[BepInPlugins]]. If that is done, there is only a small chance doing that will ''not'' turn your game into an firecracker plant. * <code>MonoModRules</code> described in MonoMod readme does not seem to coexist nicely with BepInEx. ''More testing is required to narrow down where things go terribly wrong.'' == Usage == MMPatches have to be named as following: <code>[anything].mm.dll</code>. They are loaded from <code>Rain World/BepInEx/monomod/</code> ''at preloader time''. [[BOI]] renames files automatically in a futile attempt to make the process more intuitive for the end user. [[Category:Code Mods]] 41b8acde61863c2dddf93088482a9d40f0c7f612 Category:RW-Specific Tools 14 108 150 2022-08-07T13:51:54Z Thalber 3 Created page with "This category contains pages describing community-made modding tools that are tailored for Rain World modding specific usecases (Possible items: external program, Krita workflow for easily drawing editor props, devtools menu extension library, etc)." wikitext text/x-wiki This category contains pages describing community-made modding tools that are tailored for Rain World modding specific usecases (Possible items: external program, Krita workflow for easily drawing editor props, devtools menu extension library, etc). e8c357b87ed78d1132cf27c5af96262e9bbfba9a Hooking a Property 0 109 151 2022-08-07T13:57:45Z Cashewww 2 Redirected page to [[MonoMod RuntimeDetour]] wikitext text/x-wiki #REDIRECT [[MonoMod RuntimeDetour]] 818deca1e886ed527e79931bd0df49f54745bbec BOI 0 110 152 2022-08-07T14:15:31Z Thalber 3 Created page with "'''BOI''' ''(n abbreviation of a horrendous pun)'' is an external mod manager for [[BepInEx]] initially created with the intent of making migration from [[Partiality]] easier. Glued together in Windows Forms and erratically maintained by a terminally clueless specimen since late 2020, it is a tall tower of bodges that somehow still stands. A hatchling-friendly tutorial to using it can be found [https://youtu.be/brDN_8uN6-U on YouTube]. Source code and releases can be f..." wikitext text/x-wiki '''BOI''' ''(n abbreviation of a horrendous pun)'' is an external mod manager for [[BepInEx]] initially created with the intent of making migration from [[Partiality]] easier. Glued together in Windows Forms and erratically maintained by a terminally clueless specimen since late 2020, it is a tall tower of bodges that somehow still stands. A hatchling-friendly tutorial to using it can be found [https://youtu.be/brDN_8uN6-U on YouTube]. Source code and releases can be found [https://github.com/Rain-World-Modding/BOI on GitHub]. == Features == === GUI wrapper === BOI has a somewhat straightforward UI for loading/enabling/disabling mods of most common kinds. It imitates the folder behaviour of [[Partiality]] (everything is stored in <code>Rain World/Mods/</code> before being moved to BepInEx active dirs) and attempts to automate some actions counterintuitive to the end user (like renaming assembly files for [[MonoModPatches]]). === Auto-installer === BOI can quickly install a latest valid [[BepInEx]] package and some of the more commonly used mods from [[AUDB]]. === Misc === * Detecting potentially faulty mods * Save state backups * Mod tags and bulk toggling * Post-PL folder cleanup * GUI wrappers for some mod configs [[Category:RW-Specific tools]] 81ed7721a82b263120499911aaf2a6cf62fcd21d 153 152 2022-08-07T14:15:51Z Thalber 3 wikitext text/x-wiki '''BOI''' ''(an abbreviation of a horrendous pun)'' is an external mod manager for [[BepInEx]] initially created with the intent of making migration from [[Partiality]] easier. Glued together in Windows Forms and erratically maintained by a terminally clueless specimen since late 2020, it is a tall tower of bodges that somehow still stands. A hatchling-friendly tutorial to using it can be found [https://youtu.be/brDN_8uN6-U on YouTube]. Source code and releases can be found [https://github.com/Rain-World-Modding/BOI on GitHub]. == Features == === GUI wrapper === BOI has a somewhat straightforward UI for loading/enabling/disabling mods of most common kinds. It imitates the folder behaviour of [[Partiality]] (everything is stored in <code>Rain World/Mods/</code> before being moved to BepInEx active dirs) and attempts to automate some actions counterintuitive to the end user (like renaming assembly files for [[MonoModPatches]]). === Auto-installer === BOI can quickly install a latest valid [[BepInEx]] package and some of the more commonly used mods from [[AUDB]]. === Misc === * Detecting potentially faulty mods * Save state backups * Mod tags and bulk toggling * Post-PL folder cleanup * GUI wrappers for some mod configs [[Category:RW-Specific tools]] 1abee89da03e4831f2db9c0c52f0006b8bac73e6 154 153 2022-08-07T14:17:39Z Thalber 3 wikitext text/x-wiki '''BOI''' ''(an abbreviation of a horrendous pun)'' is an external mod manager for [[BepInEx]] initially created with the intent of making migration from [[Partiality]] easier. Glued together in Windows Forms and erratically maintained by a terminally clueless specimen since late 2020, it is a tall tower of bodges that somehow still stands. A hatchling-friendly tutorial to using it can be found [https://youtu.be/brDN_8uN6-U on YouTube]. Source code and releases can be found [https://github.com/Rain-World-Modding/BOI on GitHub]. == Features == === GUI wrapper === BOI has a somewhat straightforward UI for loading/enabling/disabling mods of most common kinds. It imitates the folder behaviour of [[Partiality]] (everything is stored in <code>Rain World/Mods/</code> before being moved to BepInEx active dirs) and attempts to automate some actions counterintuitive to the end user (like renaming assembly files for [[MonoModPatches]]). === Auto-installer === BOI can quickly install a latest valid [[BepInEx]] package and some of the more commonly used mods from [[AUDB]]. === Misc === * Detecting potentially faulty mods * Save state backups * Mod tags and bulk toggling * Post-PL folder cleanup * GUI wrappers for some mod configs [[Category:RW-Specific Tools]] d669effe7ae3b80e5930e75632aabc23c3e248ec 163 154 2022-08-07T14:32:51Z Thalber 3 wikitext text/x-wiki '''BOI''' ''(an abbreviation of a horrendous pun)'' is an external mod manager for [[BepInEx]] initially created with the intent of making migration from [[Partiality]] easier. Glued together in Windows Forms and erratically maintained by a terminally clueless specimen since late 2020, it is a tall tower of bodges that somehow still stands. A hatchling-friendly tutorial to using it can be found [https://youtu.be/brDN_8uN6-U on YouTube]. Source code and releases can be found [https://github.com/Rain-World-Modding/BOI on GitHub]. == Features == === GUI wrapper === BOI has a somewhat straightforward UI for loading/enabling/disabling mods of most common kinds. It imitates the folder behaviour of [[Partiality]] (everything is stored in <code>Rain World/Mods/</code> before being moved to BepInEx active dirs) and attempts to automate some actions counterintuitive to the end user (like renaming assembly files for [[MonoModPatches]]). === Auto-installer === BOI can quickly install a latest valid [[BepInEx]] package and some of the more commonly used mods from [[AUDB]]. === Misc === * Detecting potentially faulty mods * Save state backups * Mod tags and bulk toggling * Post-PL folder cleanup * GUI wrappers for some mod configs == Installation and usage == The app is unpack-and-run. Antiviruses sometimes pick up the executable as a potential trojan downloader (it's not, ignore the warnings). It is recommended (but not required) to keep BOI outside the game directory. Starting with version 0.1.7.2, it can update itself from GitHub releases shortly after exiting. [[Category:RW-Specific Tools]] 3afe598ae3ebb33b7ff814630683630ca85a5bd4 MonoMod RuntimeDetour 0 111 155 2022-08-07T14:18:40Z Cashewww 2 added runtimedetour page wikitext text/x-wiki RuntimeDetour is a tool for "raw" hooking. For procedures/functions in Rain World's Assembly-CSharp.dll, the tools provided by HOOKS-Assembly-CSharp.dll's <code>On</code> namespace are sufficient. However, HOOKS-Assembly-CSharp.dll doesn't provide tools for hooking the game's ''properties'', or anything from other mods, Unity, etc. (though if there's an alternative you can do with hooking only the game's assembly, that is preferable). This is where MonoMod's RuntimeDetour comes into play. == Example == In this example, we'll look at hooking the getter of the <code>OverseerGraphics.MainColor</code> property from the game's assembly. First, reference <code>BepInEx/core/MonoMod.RuntimeDetour.dll</code> in your project. In the examples, we'll have some imports at the top of the file: <syntaxhighlight lang="csharp"> using System.Reflection; using MonoMod.RuntimeDetour; </syntaxhighlight> <br> Now, we need to write our own delegate for the original getter of the property: <syntaxhighlight lang="csharp"> public delegate Color orig_MainColor(OverseerGraphics self); </syntaxhighlight> Note that the return type of the delegate matches the type of our target property, and it has a single parameter: the instance of <code>OverseerGraphics</code> concerned (as the property is not static). <br> We can now get to writing our hook. We're going to return a pretty Color so that all of our overseers are pretty: <syntaxhighlight lang="csharp"> public static Color OverseerGraphics_MainColor_get(orig_MainColor orig, OverseerGraphics self) { return new Color(0.6f, 0.28f, 0.46f); } </syntaxhighlight> Note that the first parameter is the type of our new delegate. To call the original property getter within our hook, simply call <code>orig</code> (and be sure to pass in <code>self</code>). <br> For this all to work, we need to add the last important step in the <code>OnEnable</code> of our mod (or another method that's called inside/after it). <syntaxhighlight lang="csharp"> BindingFlags propFlags = BindingFlags.Instance | BindingFlags.Public; BindingFlags myMethodFlags = BindingFlags.Static | BindingFlags.Public; void OnEnable() { Hook overseerColourHook = new Hook( typeof(OverseerGraphics).GetProperty("MainColor", propFlags).GetGetMethod(), typeof(ClassThatContainsNewHook).GetMethod("OverseerGraphics_MainColor_get", myMethodFlags) ); } </syntaxhighlight> aab8ee43ef711b64d4f38190bea354456ccc0599 157 155 2022-08-07T14:24:56Z Cashewww 2 added to code cat wikitext text/x-wiki RuntimeDetour is a tool for "raw" hooking. For procedures/functions in Rain World's Assembly-CSharp.dll, the tools provided by HOOKS-Assembly-CSharp.dll's <code>On</code> namespace are sufficient. However, HOOKS-Assembly-CSharp.dll doesn't provide tools for hooking the game's ''properties'', or anything from other mods, Unity, etc. (though if there's an alternative you can do with hooking only the game's assembly, that is preferable). This is where MonoMod's RuntimeDetour comes into play. == Example == In this example, we'll look at hooking the getter of the <code>OverseerGraphics.MainColor</code> property from the game's assembly. First, reference <code>BepInEx/core/MonoMod.RuntimeDetour.dll</code> in your project. In the examples, we'll have some imports at the top of the file: <syntaxhighlight lang="csharp"> using System.Reflection; using MonoMod.RuntimeDetour; </syntaxhighlight> <br> Now, we need to write our own delegate for the original getter of the property: <syntaxhighlight lang="csharp"> public delegate Color orig_MainColor(OverseerGraphics self); </syntaxhighlight> Note that the return type of the delegate matches the type of our target property, and it has a single parameter: the instance of <code>OverseerGraphics</code> concerned (as the property is not static). <br> We can now get to writing our hook. We're going to return a pretty Color so that all of our overseers are pretty: <syntaxhighlight lang="csharp"> public static Color OverseerGraphics_MainColor_get(orig_MainColor orig, OverseerGraphics self) { return new Color(0.6f, 0.28f, 0.46f); } </syntaxhighlight> Note that the first parameter is the type of our new delegate. To call the original property getter within our hook, simply call <code>orig</code> (and be sure to pass in <code>self</code>). <br> For this all to work, we need to add the last important step in the <code>OnEnable</code> of our mod (or another method that's called inside/after it). <syntaxhighlight lang="csharp"> BindingFlags propFlags = BindingFlags.Instance | BindingFlags.Public; BindingFlags myMethodFlags = BindingFlags.Static | BindingFlags.Public; void OnEnable() { Hook overseerColourHook = new Hook( typeof(OverseerGraphics).GetProperty("MainColor", propFlags).GetGetMethod(), typeof(ClassThatContainsNewHook).GetMethod("OverseerGraphics_MainColor_get", myMethodFlags) ); } </syntaxhighlight> [[Category:Code Mods]] e00fe1a96d734725f5771c1a2e96826e022346d9 160 157 2022-08-07T14:26:35Z Cashewww 2 added monomod docs link wikitext text/x-wiki RuntimeDetour is a tool for "raw" hooking. For procedures/functions in Rain World's Assembly-CSharp.dll, the tools provided by HOOKS-Assembly-CSharp.dll's <code>On</code> namespace are sufficient. Further information about this topic can be found in [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md the official MonoMod docs]. However, HOOKS-Assembly-CSharp.dll doesn't provide tools for hooking the game's ''properties'', or anything from other mods, Unity, etc. (though if there's an alternative you can do with hooking only the game's assembly, that is preferable). This is where MonoMod's RuntimeDetour comes into play. == Example == In this example, we'll look at hooking the getter of the <code>OverseerGraphics.MainColor</code> property from the game's assembly. First, reference <code>BepInEx/core/MonoMod.RuntimeDetour.dll</code> in your project. In the examples, we'll have some imports at the top of the file: <syntaxhighlight lang="csharp"> using System.Reflection; using MonoMod.RuntimeDetour; </syntaxhighlight> <br> Now, we need to write our own delegate for the original getter of the property: <syntaxhighlight lang="csharp"> public delegate Color orig_MainColor(OverseerGraphics self); </syntaxhighlight> Note that the return type of the delegate matches the type of our target property, and it has a single parameter: the instance of <code>OverseerGraphics</code> concerned (as the property is not static). <br> We can now get to writing our hook. We're going to return a pretty Color so that all of our overseers are pretty: <syntaxhighlight lang="csharp"> public static Color OverseerGraphics_MainColor_get(orig_MainColor orig, OverseerGraphics self) { return new Color(0.6f, 0.28f, 0.46f); } </syntaxhighlight> Note that the first parameter is the type of our new delegate. To call the original property getter within our hook, simply call <code>orig</code> (and be sure to pass in <code>self</code>). <br> For this all to work, we need to add the last important step in the <code>OnEnable</code> of our mod (or another method that's called inside/after it). <syntaxhighlight lang="csharp"> BindingFlags propFlags = BindingFlags.Instance | BindingFlags.Public; BindingFlags myMethodFlags = BindingFlags.Static | BindingFlags.Public; void OnEnable() { Hook overseerColourHook = new Hook( typeof(OverseerGraphics).GetProperty("MainColor", propFlags).GetGetMethod(), typeof(ClassThatContainsNewHook).GetMethod("OverseerGraphics_MainColor_get", myMethodFlags) ); } </syntaxhighlight> [[Category:Code Mods]] 811087cb121eedcab72c69cf293e72fbe542e58a 162 160 2022-08-07T14:27:06Z Cashewww 2 moved docs link wikitext text/x-wiki RuntimeDetour is a tool for "raw" hooking. For procedures/functions in Rain World's Assembly-CSharp.dll, the tools provided by HOOKS-Assembly-CSharp.dll's <code>On</code> namespace are sufficient. However, HOOKS-Assembly-CSharp.dll doesn't provide tools for hooking the game's ''properties'', or anything from other mods, Unity, etc. (though if there's an alternative you can do with hooking only the game's assembly, that is preferable). This is where MonoMod's RuntimeDetour comes into play. Further information about this topic can be found in [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md the official MonoMod docs]. == Example == In this example, we'll look at hooking the getter of the <code>OverseerGraphics.MainColor</code> property from the game's assembly. First, reference <code>BepInEx/core/MonoMod.RuntimeDetour.dll</code> in your project. In the examples, we'll have some imports at the top of the file: <syntaxhighlight lang="csharp"> using System.Reflection; using MonoMod.RuntimeDetour; </syntaxhighlight> <br> Now, we need to write our own delegate for the original getter of the property: <syntaxhighlight lang="csharp"> public delegate Color orig_MainColor(OverseerGraphics self); </syntaxhighlight> Note that the return type of the delegate matches the type of our target property, and it has a single parameter: the instance of <code>OverseerGraphics</code> concerned (as the property is not static). <br> We can now get to writing our hook. We're going to return a pretty Color so that all of our overseers are pretty: <syntaxhighlight lang="csharp"> public static Color OverseerGraphics_MainColor_get(orig_MainColor orig, OverseerGraphics self) { return new Color(0.6f, 0.28f, 0.46f); } </syntaxhighlight> Note that the first parameter is the type of our new delegate. To call the original property getter within our hook, simply call <code>orig</code> (and be sure to pass in <code>self</code>). <br> For this all to work, we need to add the last important step in the <code>OnEnable</code> of our mod (or another method that's called inside/after it). <syntaxhighlight lang="csharp"> BindingFlags propFlags = BindingFlags.Instance | BindingFlags.Public; BindingFlags myMethodFlags = BindingFlags.Static | BindingFlags.Public; void OnEnable() { Hook overseerColourHook = new Hook( typeof(OverseerGraphics).GetProperty("MainColor", propFlags).GetGetMethod(), typeof(ClassThatContainsNewHook).GetMethod("OverseerGraphics_MainColor_get", myMethodFlags) ); } </syntaxhighlight> [[Category:Code Mods]] 4ae49ac2ba9bee0de8b721c99ced5235428c30a8 BepInPlugins 0 95 156 149 2022-08-07T14:23:02Z Cashewww 2 /* RuntimeDetour */ wikitext text/x-wiki BepInPlugins are a kind of game mod native to [[BepInEx]]. They are not compatible with Partiality. They should be placed in <code>Rain World/BepInEx/plugins</code>. == Creating a BepInPlugin == === Prerequisites === * A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary) * Rain World with RW BepInEx set up - see [[BepInEx|here]]. * Some kind of .NET programming environment, probably Visual Studio if you're on Windows, or Visual Studio Code for Linux/Mac. The guide below will assume you're already comfortable with the first prerequisite and your editor and environment of choice. ** The .NET Development pack for Visual Studio (or similar for other environments - you need to be able to use .NET Framework 3.5) === Step 1 - The project === Create a new C# .NET Framework 3.5 Class Library project in your IDE. You will then need to [https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019 add some references]. It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/plugins/PartialityWrapper/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/core/BepInEx.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/Assembly-CSharp.dll</code> - note: you will need to modify this before accessing private members; see the section "Replacement of Publicity Stunt" on [[BepInEx]] page. === Step 2 - The BepInPlugin class === In a your new C# file, make a public class that has the <code>BepInEx.BepInPlugin</code> attribute and inherits from <code>BepInEx.BaseUnityPlugin</code> . The <code>BaseUnityPlugin</code> class inherits from <code>MonoBehaviour</code>, so you can use standard Unity script methods such as <code>OnEnable</code> and <code>OnDisable</code> in this class. The GUID should be unique to this plugin: something like "scholar" could be popular, which may result in BepInEx not loading your mod. Usually, people opt for the <code>username.mode_name</code> format. <syntaxhighlight lang="csharp"> using BepInEx; namespace SomeMod {     [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] // (GUID, mod name, mod version)     public class MyModName : BaseUnityPlugin     {     } } </syntaxhighlight> === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example:<syntaxhighlight lang="csharp"> [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] public class MyMod : BaseUnityPlugin {     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         /* This method will be subscribed to Player.Update. */         orig(self, eu);         /* Calling orig is what allows the original method and          * other hooks to the same method do their thing.          * Not calling this is almost always undesirable, and          * can cause big issues.          *   You can execute code before or after the call of          * orig as necessary.          */     } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote>Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and copy the mod's DLL file from wherever your build output is to <code>Rain World/BepInEx/plugins/</code> and run Rain World. == Enums == Due to their abundance in Rain World's code and their general usefulness in state machines, it's very possible that at some point you'll want to add your own value to an enum. To do that, you can use [[EnumExtender]]. == Advanced Techniques == === IL Hooking === IL hooking can be used to modify the Intermediate Language (IL) instructions of the game at runtime. This allows advanced editing of individual instructions within the game code. Risk of Thunder's guide to IL hooking can be found [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ here]. === RuntimeDetour === RuntimeDetour can be used to hook methods not covered by HOOKS-Assembly-CSharp.dll, as well as property getters and setters. A brief guide can be found on the [[MonoMod RuntimeDetour]] page. MonoMod's RuntimeDetour guide can be found [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md here]. === Harmony Patching === Harmony patching is a form of runtime patching. The HarmonyX wiki can be found [https://github.com/BepInEx/HarmonyX/wiki here]. [[Category:Code Mods]] 3cab057f5e2301c7ae2892e22212a6fbbf29a2c3 MonoMod Patches 0 107 158 148 2022-08-07T14:25:12Z Thalber 3 Thalber moved page [[MonoModPatches]] to [[MonoMod Patches]] wikitext text/x-wiki {{Cleanup}} '''MonoModPatches''' or '''MMPatches''' are one of the simplest ways of modifying vanilla code. They can be used with current version of our [[BepInEx]] package. MonoMod's [https://github.com/MonoMod/MonoMod/blob/master/README.md README] contains a description of this method. Short summary and RW-specific aspects are presented below. == Creation == * Create a project referencing both <code>MonoMod.exe</code> and <code>AssemblyCSharp.dll</code> * Create a type deriving from target class * Mark your class for patching. This can be done in two ways: *# Place your class in the exact same namespace and name it <code>patch_OriginalNamehere</code> (<code>patch_Player</code> to patch <code>Player</code>) *# Denote your class with <code>MonoModPatch</code> attribute like the following example <!--(<code>Custom</code>)--> <syntaxhighlight lang="csharp"> [MonoModPatch("global::Player")] //"global::" is the namespace for classes appearing "without a namespace" public class CustomPlayer : Player { } </syntaxhighlight> * For every method to patch, use the following pattern: <syntaxhighlight lang="csharp"> [MonoModPatch("global::Player")] public class CustomPlayer : Player { public extern void orig_Update(bool eu); public override void Update(bool eu) { //do your things orig_Update(eu); // original method body is inserted at the site of this call. Omit to not use original code at all (also disables layering MMPatches). //do your things } } </syntaxhighlight> To access a private member, create one with matching signature (type / name / params etc) and denote it with <code>MonoModIgnore</code> attribute. To patch a non-override public method, use <code>new</code> to hide the vanilla method for the compiler. === Things to note === * MMPatches should not be shipped in the same assembly as partmods/[[BepInPlugins]]. If that is done, there is only a small chance doing that will ''not'' turn your game into an firecracker plant. * <code>MonoModRules</code> described in MonoMod readme does not seem to coexist nicely with BepInEx. ''More testing is required to narrow down where things go terribly wrong.'' == Usage == MMPatches have to be named as following: <code>[anything].mm.dll</code>. They are loaded from <code>Rain World/BepInEx/monomod/</code> ''at preloader time''. [[BOI]] renames files automatically in a futile attempt to make the process more intuitive for the end user. [[Category:Code Mods]] 41b8acde61863c2dddf93088482a9d40f0c7f612 MonoModPatches 0 112 159 2022-08-07T14:25:12Z Thalber 3 Thalber moved page [[MonoModPatches]] to [[MonoMod Patches]] wikitext text/x-wiki #REDIRECT [[MonoMod Patches]] c5b26983156ae5c2ecde55deea904d406d7f2252 BepInEx 0 98 161 135 2022-08-07T14:26:36Z Thalber 3 /* Using Mods */ wikitext text/x-wiki BepInEx is a mod loader and plugin framework primarily for Unity and XNA games. '''It is important to note''' that the generic BepInEx releases are not directly compatible with Partiality Mods, which make up a large portion of mods for Rain World v1.5. Currently, it is imperative you use a specially modified version of BepInEx to use the majority of existing Rain World mods. '''Another note for Linux/Steam Deck users:''' as Rain World is not natively available for Linux (and Steam Deck is powered by Linux), extra steps are required for installation. [https://gist.github.com/PJB3005/a7b635f171bd34f18a28885afa8f6e8e This guide] will help you set up Realm (a package which includes BepInEx) for Rain World on your Linux device with the help of Steam Proton/WINE. There are two ways of getting an appropriate version of BepInEx. '''Either''' use the [[#Installation|Installation]] section to install RW BepInEx '''OR''' download [https://github.com/Dual-Iron/RwModLoader#readme Realm]. Realm has an in-game mod management interface, but is currently incompatible with a small number of mods. == Installation == ''Tip: If you got the game from Steam then the default location for the Rain World folder is <code>C:\Program Files (x86)\Steam\steamapps\common\Rain World</code>, but this will be different if you changed the installation settings.'' All of the steps below for installing RW BepInEx and BOI (an app that helps manage mod files) are presented in [https://youtu.be/brDN_8uN6-U this video]. [[File:BepInEx Installation.png|alt=The BepInEx folder, doorstep_config.ini, and winhttp.dll should be in the Rain World folder. |thumb|474x474px|This is what the Rain World folder should look like after installing BepInEx. ]] If you have not installed Partiality for the current installation of Rain World, skip to step 2. # Go to the <code>Rain World/RainWorld_Data</code> folder, delete the folder called <code>Managed</code>, and rename <code>Managed_backup</code> to <code>Managed</code>. # [https://beestuff.pythonanywhere.com/audb/api/v2/bepinex/download Download RW BepInEx]. # Extract the contents of the .zip archive and copy its ''contents'' to the Rain World folder. # At this point, your Rain World folder should look like the image on the right. You can also check the installation by running the game as you normally would - if a file called LogOutput.log is now in the BepInEx folder, then BepInEx is starting up. == Using Mods == === Option 1: BOI === [[BOI]] is a graphical application for mod management with RW BepInEx. It also includes a few other tools such as save file management and ability to change [[Dev Tools]] settings. It can be installed from [https://github.com/Rain-World-Modding/BOI/releases here] - download the first .zip and extract its contents anywhere (though preferably not inside the Rain World folder). === Option 2: Realm === Realm is a package that includes BepInEx and an in-game mod management interface. It allows for download, installation, and reloading of many mods in-game. See [https://github.com/Dual-Iron/RwModLoader#readme the Realm readme] for more information. === Option 3: Moving Files === * [[BepInPlugins]] and [[Partiality|Partiality Mods]] must go in <code>BepInEx/plugins</code> * [[MonoMod Patches]] must be renamed to the format <code>Assembly-CSharp.[mod name].mm.dll</code> and must go in <code>BepInEx/monomod</code> * Preloader patchers must go in <code>BepInEx/patchers</code> 623c34bbba72986fe03f4300ae0b1d6ab280e27d RegionKit 0 113 164 2022-08-07T15:02:22Z Thalber 3 Created page with "'''RegionKit''' is a commonly used library for region makers, containing room effects, objects and code interfaces useful for making regions and supporting content. Source, guides, full feature list and releases can be found [https://github.com/DryCryCrystal/Region-Kit here] == Features == * Several bugfixes for vanilla objects / effects * Adds custom arena management through text files in subfolders of <code>/Levels/</code> * Carries a copy of Placed Objects Manage..." wikitext text/x-wiki '''RegionKit''' is a commonly used library for region makers, containing room effects, objects and code interfaces useful for making regions and supporting content. Source, guides, full feature list and releases can be found [https://github.com/DryCryCrystal/Region-Kit here] == Features == * Several bugfixes for vanilla objects / effects * Adds custom arena management through text files in subfolders of <code>/Levels/</code> * Carries a copy of [[Placed Objects Manager]]<!--, [[CustomSpritesLoader]]--> and [[ExtendedGates]] frameworks by Henpemaz * A generic particle system and a simple framework for adding custom * Asset-driven custom echo inserter * Implements all objects from The Mast, Aether Ridge, Arid Barrens and Flooded Assembly, superceeding their standalone DLL files for the first 3 * Contains several misc objects and effects == Installation and usage == Installed as any other [[BepInPlugins|BepInEx plugin]]. Depends on EnumExtender. Has autoupdate support. [[Category:Code Mods]] [[Category:Dependencies]] ed7b7241e15429c21ac39263b1559fbbfef8e32b 165 164 2022-08-07T15:03:43Z Thalber 3 wikitext text/x-wiki '''RegionKit''' is a commonly used library for region makers, containing ready room effects, objects and code useful for making regions and supporting content. Source, guides, full feature list and releases can be found [https://github.com/DryCryCrystal/Region-Kit here] == Features == * Several bugfixes for vanilla objects / effects * Adds custom arena management through text files in subfolders of <code>/Levels/</code> * Carries a copy of [[Placed Objects Manager]]<!--, [[CustomSpritesLoader]]--> and [[ExtendedGates]] frameworks by Henpemaz * A generic particle system and a simple framework for adding custom * Asset-driven custom echo inserter * Implements all objects from The Mast, Aether Ridge, Arid Barrens and Flooded Assembly, superceeding their standalone DLL files for the first 3 * Contains several misc objects and effects == Installation and usage == Installed as any other [[BepInPlugins|BepInEx plugin]]. Depends on EnumExtender. Has autoupdate support. [[Category:Code Mods]] [[Category:Dependencies]] bf2434cd1b58ea59e21d662ed11e40e2eebc6cce 171 165 2022-08-09T17:51:53Z DryCryCrystal 10 RK requires CRS, fixed some grammar wikitext text/x-wiki '''RegionKit''' is a commonly used library for region makers, containing ready room effects, objects and code useful for making regions and supporting content. Source, guides, full feature list, and releases can be found [https://github.com/DryCryCrystal/Region-Kit here] == Features == * Several bugfixes for vanilla objects/effects * Adds custom arena management through text files in subfolders of <code>/Levels/</code> * Carries a copy of [[Placed Objects Manager]]<!--, [[CustomSpritesLoader]]--> and [[ExtendedGates]] frameworks by Henpemaz * A generic particle system and a simple framework for adding custom * Asset-driven custom echo inserter * Implements all objects from The Mast, Aether Ridge, Arid Barrens, and Flooded Assembly, superseding their standalone DLL files for the first 3 * Contains several misc objects and effects == Installation and usage == Installed as any other [[BepInPlugins|BepInEx plugin]]. Depends on EnumExtender and Custom Region Support. Has autoupdate support. [[Category:Code Mods]] [[Category:Dependencies]] a65c121b856900e584ce0eeb5f573d3824b186e5 172 171 2022-08-10T16:34:33Z Thalber 3 wikitext text/x-wiki '''RegionKit''' is a commonly used library for region makers, containing ready room effects, objects and code useful for making regions and supporting content. Source, guides, full feature list, and releases can be found [https://github.com/DryCryCrystal/Region-Kit here] == Features == * Several bugfixes for vanilla objects/effects * Adds custom arena management through text files in subfolders of <code>/Levels/</code> * Carries a copy of [[Placed Objects Manager]]<!--, [[CustomSpritesLoader]]--> and [[ExtendedGates]] frameworks by Henpemaz * A generic particle system and a simple framework for adding custom * Asset-driven custom echo inserter * Implements all objects from The Mast, Aether Ridge, Arid Barrens, and Flooded Assembly, superseding their standalone DLL files for the first 3 * Contains several misc objects and effects == Installation and usage == Installed as any other [[BepInPlugins|BepInEx plugin]]. Depends on [[EnumExtender]] and [[Custom Region Support]]. Has autoupdate support. [[Category:Code Mods]] [[Category:Dependencies]] e841a3dd678ea04988111e64c5a2d971e4e0c0da Custom Regions Support 0 101 166 139 2022-08-07T18:48:16Z Thalber 3 /* Runtime worldfile merging */ wikitext text/x-wiki {{Cleanup}} '''Custom Regions Support''' or '''CRS''' is a library/util mod that was created as an easier way to install [[Content Mods]], replacing file merging. It allows to install multiple region mods at once easily, quickly toggle them, and makes region development less messy. As of now, it is the primary way of installing any and all custom regions, and many of them are ''CRS-exclusive''. Full up-to-date README, source code and CRS-specific technical reference for modders can be found [[https://github.com/Garrakx/Custom-Regions on its GitHub]]. == Features == === Runtime worldfile merging === ''For basics of region architecture, see [[World file format]]'' CRS attempts to smartly combine region world files and avoid room connectivity conflicts. It is the most effective if region mods don't distribute full modified copies of WORLD_XX.txt files for conflict-prone connection (such as vanilla region's WORLD_XX, when a modded region connects to it), and instead ''only include lines that need to be changed or added''. This is commonly referred to as "refining worldfiles". In addition to connection files, it can also merge region property files. === In-game downloader === CRS config menu allows the user to install most region packs from inside the game in one click, including their dependency DLLs, and also quickly toggle installed packs on and off. Downloader menu is reshuffled every day to give every CRS-published region a shot. === Region-conditional connections === Connections may be toggled depending on if a certain region is present: <syntaxhighlight lang=""> ROOMS (TM, !BL)roomA : roomB, roomD //only used if TM is installed and BL is not ENDROOMS </syntaxhighlight> This can be combined with unused vanilla behaviour of character-specific connections. === Connection fixer === Starting with v0.9.xx, CRS can attempt to fix some broken connections. This behaviour isn't a catchall but can make some conflicts less lethal. === Additional asset loading === CRS allows easily loading assets commonly bundled with most regions, such as music files, region splash art for passage/regions map screens, decals etc. === Misc === * Making previously hardcoded settings (electric gates, albino colouring on creatures, chance of salamander colouring etc) configurable with json files * Removing creature spawns * No-code addition of custom pearls * Adding unlockable arenas 5fff5fec532cf2656735f40f8e279225d3d35fcb World File Format 0 114 167 2022-08-07T19:31:12Z Thalber 3 Created page with "{{Cleanup}} [[File:regionFormat.png|thumb|right|alt=regionFormat|regionFormat]] This page describes worldfile format for RW regions. The world_XX.txt file is present in every region Rain World loads, and determines various room settings such as their pipe connections, the spawns of enemies, and specific flags like shelters and gates. NOTE: Creature spawns for the region are generated when you first enter it on a save. Changing room connections or creature spawns in..." wikitext text/x-wiki {{Cleanup}} [[File:regionFormat.png|thumb|right|alt=regionFormat|regionFormat]] This page describes worldfile format for RW regions. The world_XX.txt file is present in every region Rain World loads, and determines various room settings such as their pipe connections, the spawns of enemies, and specific flags like shelters and gates. NOTE: Creature spawns for the region are generated when you first enter it on a save. Changing room connections or creature spawns in WORLD_XX after that corrupts save data. '''Reset your saveslot or revert your save to before you entered to avoid bugs'''. == Room Connections == Room connections section is bounded by <code>ROOMS</code> and <code>END ROOMS</code> tags. These control which pipe entrance leads to what room, and vice versa. Unique room flags that specify certain attributes about the room (such as if it is a shelter or a gate room) are set here as well. The format is as follows: <syntaxhighlight lang="">ROOM : door0, door1, door2, etc : FLAG </syntaxhighlight> === Examples === A standard room with two room-connecting pipes. These will form the bulk of your region. <syntaxhighlight lang="">TR_T07 : TR_T01, TR_P02 </syntaxhighlight> A standard room, with five doors. However, pipes 1, 2 and 3 have no connection. Each pipe inside a room has a specific number starting from 0. These can be viewed using the [[Dev Tools]]' map tab, or by entering the room with dev tools enabled and pressing M. <syntaxhighlight lang="">TR_W19 : TR_L05, DISCONNECTED, DISCONNECTED, DISCONNECTED, TR_W18 </syntaxhighlight> A shelter. These rooms will often be copied from other regions when you are first learning how to make a region. All vanilla save rooms have a single door. <syntaxhighlight lang="">TR_S01 : TR_P01 : SHELTER </syntaxhighlight> A region gate. Doors on the other side of the gate are set to DISCONNECTED. They will automatically be shown as connected doors at runtime. If you need to show a save room door specifically on the other side of the gate, you can use the ExitSymbolShelter object, in the dev tool’s [[dev-tools/Objects.html|object tab]] to change the door symbols as required. <syntaxhighlight lang="">GATE_SS_TR : DISCONNECTED, TR_L07 : GATE </syntaxhighlight> A swarm room allows batflies to spawn in the room, as long as the map contains bat nests. If the room has bat nests but is not marked as a swarm room, those nests will always be inactive. The dev tools map tab provides the options needed to control where they will migrate and rooms they will avoid. <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> A scavenger outpost. Use in conjunction with ScavengerOutpost placedObject to create a scavenger toll. <syntaxhighlight lang="">SU_C02 : SU_A45, SU_A07 : SCAVOUTPOST </syntaxhighlight> === Understanding door connections === [[File:regionFormatConnection.png|thumb|none|alt=regionFormatConnection|regionFormatConnection]] For a door to be properly connected, both ends must point to each other using valid doors. For this example, both rooms will have two doors. Door0 will be on the left, and door1 on the right. Door indices are decided specifically for your room, so be sure to check in game how your doors have been assigned by the [[Level Editor]]. The DT Map tab can also be used to see the links between doors. As in the picture to the right. Properly connected doors will show both lines pointing to the set door on the other end. Doors with incorrect links will point off to the bottom right <!--(A disconnected door will also do this,)--> <!--do fucking what--> and a door connected to another room, but that room has no door back (or lacks enough doors!) will point to the center of the room on the map tab page. <syntaxhighlight lang=""> RG_ROOM1 : DISCONNECTED, RG_ROOM2 </syntaxhighlight> <syntaxhighlight lang=""> RG_ROOM2: RG_ROOM1 </syntaxhighlight> Room1 will have its right hand door connected to Room2. Because of this, we need to use DISCONNECTED as a placeholder for its left hand door, door0. Then set door1 to connect to Room2 Room2 will connect to Room1 using door0. Due to this, we do not need to define the right hand door. It will assume it to be disconnected. === Room Tags === Room tags assign certain properties to rooms depending on what the tag is. Tags are assigned like <syntaxhighlight lang=""> [ROOM] : [CONNECTIONS] : [TAG] </syntaxhighlight> Example: <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> {| !width="18%"| '''<u>Tag</u>''' !width="81%"| '''<u>Function</u>''' |- | SHELTER | Makes the room a shelter. When there are multiple pipes in the room: the animated door is placed at the bottom right most pipe. |- | GATE | Makes the room a gate. Entrances on the other side of the gate are set to DISCONNECTED, and are shown automatically to be connected. |- | SWARMROOM | Allows batflies to be spawned from batfly hives. |- | PERF_HEAVY | Causes the room to be abstractized quicker when player is not inside, can reduce offscreen performance toll of very large rooms. |- | SCAVOUTPOST | Makes the room into a scavenger outpost. Scavs will spawn here and only let you pass if you have a pearl. The exact outpost location is set by the “ScavengerOutpost” devtools object. |- | SCAVTRADER | Spawns a scavenger merchant into the room. Will trade items with you. The merchant is controlled by the “TradeOutpost” devtools object. |} === Important quirks to rooms and doors === When setting up your region, be sure that you always use your region’s prefix to help each room have a unique name. If not, Rain World will treat repeated names as being other rooms, and even re-use rooms from other region folders entirely. If you don’t use your region prefix, changes made with devtools can also wind up getting saved to unexpected places. To avoid these problems, always prefix your room with its region code, and give them unique names. Multiple pipes in a room may all go to the same room. However, these will all act like a single pipe, and you will not be able to set the specific destination pipes. There are no cases in vanilla Rain World where multiple pipes in the current room lead to the same next room. They will all lead to separate rooms. For example, if you had four pipes leading from one room to another. you would need to create a minimum of three unique rooms for each of the other pipes to act as an interconnection. == Creature Spawns == Creature spawn data section is bounded by <code>CREATURES</code> and <code>END CREATURES</code> tags. Rain World only creates creature spawns when you enter a region for the first time on a save<!--, or after an excessive number of cycles has passed--><!--never heard of it before, may be bogus ~thalber-->. {|class="wikitable" !align="center" width="12%"| '''Lizards''' !align="center" width="25%"| '''Insects''' !align="center" width="13%"| '''Amphibians''' !align="center" width="18%"| '''Flying''' !align="center" width="16%"| '''Plants''' !align="center" width="12%"| '''Other''' |- |align="center"| Pink |align="center"| Spider |align="center"| Salamander |align="center"| CicadaA |align="center"| PoleMimic, Mimic* |align="center"| Scavenger |- |align="center"| Green |align="center"| Small Centipede |align="center"| Leech |align="center"| CicadaB |align="center"| Tentacle, TentaclePlant* |align="center"| Lantern Mouse, Mouse* |- |align="center"| Blue |align="center"| Centipede, Centi, Cent* |align="center"| SeaLeech |align="center"| Vulture |align="center"| |align="center"| Worm, Garbage Worm* |- |align="center"| Yellow |align="center"| Red Centipede, RedCenti, RedCentipede* |align="center"| JetFish, Jetfish* |align="center"| KingVulture, King Vulture* |align="center"| |align="center"| Miros, MirosBird* |- |align="center"| White |align="center"| DropBug, Dropbug, DropWig, Dropwig* |align="center"| Snail |align="center"| Needle, Needle Worm* |align="center"| |align="center"| Tube, TubeWorm* |- |align="center"| Black |align="center"| BigSpider |align="center"| Lev, Leviathan |align="center"| SmallNeedleWorm |align="center"| |align="center"| Bro, BroLongLegs* |- |align="center"| Cyan |align="center"| SpitterSpider |align="center"| |align="center"| Cicada** |align="center"| |align="center"| Daddy, DaddyLongLegs* |- |align="center"| Red |align="center"| EggBug, Eggbug* |align="center"| |align="center"| |align="center"| |align="center"| |} (*) Interchangeable names (**) Switches between CicadaA and CicadaB) <syntaxhighlight lang=""> //Creature spawns can be specific to a certain character. (0, 1) makes something appear for monk and survivor, (2) only for hunter (character filter)ROOM : PipeNumber-Creature-{optional flags}-Count </syntaxhighlight> <span id="examples-include-1"></span> === Examples === A single green lizard, spawning from pipe 2, on all difficulties. <syntaxhighlight lang=""> SU_A10 : 2-Green </syntaxhighlight> A single red lizard, spawning from pipe 3, on Hunter only. <syntaxhighlight lang=""> (2)SU_A10 : 3-Red </syntaxhighlight> A hoard of 5 yellow lizards spawning from pipe 1, on Monk only. <syntaxhighlight lang=""> (1)SU_A10 : 1-Yellow-5 </syntaxhighlight> A Daddy longlegs spawning from pipe 4, but only on easy and normal difficulties. <syntaxhighlight lang=""> (0,1)SU_A10 : 4-Daddy </syntaxhighlight> A very angry white lizard that spawns from pipe 3, on all difficulties. the “Mean” flag can be set from 0 to 1, and will change the enemy’s personality to pursue you aggressively depending on how high it is set. <syntaxhighlight lang=""> SU_A10 : 3-White-{Mean:0.9} </syntaxhighlight> Some enemies require a unique room known as OFFSCREEN. These enemies use special doors that are automatically added to your level to move between rooms. These include vultures, scavengers, leviathans, and miros birds. This example spawns two off screen vultures. <syntaxhighlight lang=""> OFFSCREEN : 0-Vulture-2 </syntaxhighlight> Enemy flags still apply to offscreen enemies. This will spawn a very aggressive KingVulture that will rarely leave the screen if it spots slugcat, but only on Hunter. <syntaxhighlight lang=""> (2)OFFSCREEN : 0-KingVulture-{Mean:1} </syntaxhighlight> <span id="important-quirks-to-creatures"></span> ==== Important quirks to creatures: ==== Enemies may be set to spawn from the same nest pipes. However, do not be surprised if they somehow kill each other offscreen very quickly if you do this. A daddy long legs may have no problems consuming an entire hoard of yellow lizards for example. Enemies will often drag you back to their home nest pipes, but may also choose other pipes they like, even in different rooms. During the end of a cycle, almost every enemy will rush to a nearby nest, if they spawned from it or not. Many creatures that would not intuitively appear to nest in pipes, likely does so, you just never reach them before they spawn in game, or their pipes are well hidden. A direct example of this, is that wandering daddy longlegs spawn from pipes, and return to their pipes before the end of a cycle. This includes the daddies inside Five Pebbles, which makes the area significantly easier once the cycle timer has counted down entirely. It is important to understand various enemy interactions to help you build a cohesive and believable ecosystem for an area. Sandbox mode can help you learn which creature is where on the food chain. As well as looking at the interactions of creatures in other regions. Some creatures have very specific requirements for rooms they inhabit. A very game breaking example, is that big spiders and spitting spiders require the ability to reach every wall in a room in some fashion. By pole, or by invisible ceilings out of the camera. If they cannot, the game will lag very badly due to the spider’s failed pathfinding. Some creatures have a heavier performance impact on the game then others. <!--Sandbox mode can help you learn these, as it will show a notice that “too many of this creature will impact performance” when you begin to place too many.--> <!-- the arena threshold seems somewhat arbitrary in present day--> An example is that more then 4 daddy long legs on screen will often lead to lag. Unfortunate development gets around this problem by using the “stuckDaddy” object, as these daddies do not run wandering path finding checks. All creature types can be configured using the dev tool’s map editor to prefer, avoid, stay or be forbidden inside certain rooms while wandering, using Attraction tool. These spawn entries are simply where they will be created from when the player first enters a region. <span id="the-lineage-system"></span> === The Lineage System === Enemy nests may also be configured to use the lineage system. After being killed, this allows a creature to roll a dice at the end of a cycle, and in a certain percent, respawn as its next entry in the lineage. Due to the format however, you cannot decide how many enemies can spawn from the pipe. So a green lizard cannot turn into a hoard of 3 yellow lizards. Only a single yellow lizard. Enemy flags, and difficulty filters still work however. The format is as follows: <syntaxhighlight lang=""> LINEAGE : ROOM : PIPE : STARTENEMY-PERCENT, NEXTENEMY-PERCENT, FINALENEMY-0 </syntaxhighlight> PERCENT is a value between 0 and 1, and is the percent chance that the enemy will move onto its next form. You may have as many forms as you need. However, it is important to ALWAYS mark the last enemy in the lineage with a 0 percent chance to move on. Rain World will crash the moment it attempts to move to the next enemy in a lineage from the last. === Examples === A green lizard that spawns from pipe 2, that turns into a blue, and then into a red. With a 5% chance each time. <syntaxhighlight lang=""> LINEAGE : SU_B08 : 2 : Green-0.05, Blue-0.05, Red-0 </syntaxhighlight> A poleplant, with a specific height of 10 blocks, and spawning from pipe 3. That has a 10% chance to turn into a monster kelp <syntaxhighlight lang=""> LINEAGE : SU_A02 : 3 : Mimic-{10}-0.1, TentaclePlant-0 </syntaxhighlight> A empty pipe 3, that has a 1% chance to turn into a monster kelp. <syntaxhighlight lang=""> LINEAGE : SU_B02 : 3 : NONE-0.01, TentaclePlant-0 </syntaxhighlight> Lineage applies to offscreen creatures, as well as difficulties! This example from chimney canopy has a 20% chance to turn a vulture into a king vulture after being killed, but only on normal difficulty. <syntaxhighlight lang=""> (0)LINEAGE : OFFSCREEN : 0 : Vulture-0.2, KingVulture-0 </syntaxhighlight> == Bat Migration Blockages == Bat migration blockages section is bounded by <code>BAT MIGRATION BLOCKAGES</code> and <code>END BAT MIGRATION BLOCKAGES</code> tags. These are used specifically to prevent bat flies from entering a room, or pathing through the region to rooms on the other side of it. These are rarely used. However the room directly after the tutorial area in outskirts is set to be one. The format is simply to list each room line by line between the two tags. There are no unique flags. For the example in Outskirts, bat flies cannot enter room SU_A22 because it is between the tags: <syntaxhighlight lang="">BAT MIGRATION BLOCKAGES SU_A22 END BAT MIGRATION BLOCKAGES </syntaxhighlight> b4642ec69a90e737a95bc1c960df9ab88e2da5c8 169 167 2022-08-07T19:32:19Z Thalber 3 wikitext text/x-wiki {{Cleanup}} [[File:regionFormat.png|thumb|right|alt=regionFormat|regionFormat]] This page describes worldfile format for RW regions. The world_XX.txt file is present in every region Rain World loads, and determines various room settings such as their pipe connections, the spawns of enemies, and specific flags like shelters and gates. NOTE: Creature spawns for the region are generated when you first enter it on a save. Changing room connections or creature spawns in WORLD_XX after that corrupts save data. '''Reset your saveslot or revert your save to before you entered to avoid bugs'''. == Room Connections == Room connections section is bounded by <code>ROOMS</code> and <code>END ROOMS</code> tags. These control which pipe entrance leads to what room, and vice versa. Unique room flags that specify certain attributes about the room (such as if it is a shelter or a gate room) are set here as well. The format is as follows: <syntaxhighlight lang="">ROOM : door0, door1, door2, etc : FLAG </syntaxhighlight> === Examples === A standard room with two room-connecting pipes. These will form the bulk of your region. <syntaxhighlight lang="">TR_T07 : TR_T01, TR_P02 </syntaxhighlight> A standard room, with five doors. However, pipes 1, 2 and 3 have no connection. Each pipe inside a room has a specific number starting from 0. These can be viewed using the [[Dev Tools]]' map tab, or by entering the room with dev tools enabled and pressing M. <syntaxhighlight lang="">TR_W19 : TR_L05, DISCONNECTED, DISCONNECTED, DISCONNECTED, TR_W18 </syntaxhighlight> A shelter. These rooms will often be copied from other regions when you are first learning how to make a region. All vanilla save rooms have a single door. <syntaxhighlight lang="">TR_S01 : TR_P01 : SHELTER </syntaxhighlight> A region gate. Doors on the other side of the gate are set to DISCONNECTED. They will automatically be shown as connected doors at runtime. If you need to show a save room door specifically on the other side of the gate, you can use the ExitSymbolShelter object, in the dev tool’s [[dev-tools/Objects.html|object tab]] to change the door symbols as required. <syntaxhighlight lang="">GATE_SS_TR : DISCONNECTED, TR_L07 : GATE </syntaxhighlight> A swarm room allows batflies to spawn in the room, as long as the map contains bat nests. If the room has bat nests but is not marked as a swarm room, those nests will always be inactive. The dev tools map tab provides the options needed to control where they will migrate and rooms they will avoid. <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> A scavenger outpost. Use in conjunction with ScavengerOutpost placedObject to create a scavenger toll. <syntaxhighlight lang="">SU_C02 : SU_A45, SU_A07 : SCAVOUTPOST </syntaxhighlight> === Understanding door connections === [[File:regionFormatConnection.png|thumb|none|alt=regionFormatConnection|regionFormatConnection]] For a door to be properly connected, both ends must point to each other using valid doors. For this example, both rooms will have two doors. Door0 will be on the left, and door1 on the right. Door indices are decided specifically for your room, so be sure to check in game how your doors have been assigned by the [[Level Editor]]. The DT Map tab can also be used to see the links between doors. As in the picture to the right. Properly connected doors will show both lines pointing to the set door on the other end. Doors with incorrect links will point off to the bottom right <!--(A disconnected door will also do this,)--> <!--do fucking what--> and a door connected to another room, but that room has no door back (or lacks enough doors!) will point to the center of the room on the map tab page. <syntaxhighlight lang=""> RG_ROOM1 : DISCONNECTED, RG_ROOM2 </syntaxhighlight> <syntaxhighlight lang=""> RG_ROOM2: RG_ROOM1 </syntaxhighlight> Room1 will have its right hand door connected to Room2. Because of this, we need to use DISCONNECTED as a placeholder for its left hand door, door0. Then set door1 to connect to Room2 Room2 will connect to Room1 using door0. Due to this, we do not need to define the right hand door. It will assume it to be disconnected. === Room Tags === Room tags assign certain properties to rooms depending on what the tag is. Tags are assigned like <syntaxhighlight lang=""> [ROOM] : [CONNECTIONS] : [TAG] </syntaxhighlight> Example: <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> {| !width="18%"| '''<u>Tag</u>''' !width="81%"| '''<u>Function</u>''' |- | SHELTER | Makes the room a shelter. When there are multiple pipes in the room: the animated door is placed at the bottom right most pipe. |- | GATE | Makes the room a gate. Entrances on the other side of the gate are set to DISCONNECTED, and are shown automatically to be connected. |- | SWARMROOM | Allows batflies to be spawned from batfly hives. |- | PERF_HEAVY | Causes the room to be abstractized quicker when player is not inside, can reduce offscreen performance toll of very large rooms. |- | SCAVOUTPOST | Makes the room into a scavenger outpost. Scavs will spawn here and only let you pass if you have a pearl. The exact outpost location is set by the “ScavengerOutpost” devtools object. |- | SCAVTRADER | Spawns a scavenger merchant into the room. Will trade items with you. The merchant is controlled by the “TradeOutpost” devtools object. |} === Important quirks to rooms and doors === When setting up your region, be sure that you always use your region’s prefix to help each room have a unique name. If not, Rain World will treat repeated names as being other rooms, and even re-use rooms from other region folders entirely. If you don’t use your region prefix, changes made with devtools can also wind up getting saved to unexpected places. To avoid these problems, always prefix your room with its region code, and give them unique names. Multiple pipes in a room may all go to the same room. However, these will all act like a single pipe, and you will not be able to set the specific destination pipes. There are no cases in vanilla Rain World where multiple pipes in the current room lead to the same next room. They will all lead to separate rooms. For example, if you had four pipes leading from one room to another. you would need to create a minimum of three unique rooms for each of the other pipes to act as an interconnection. == Creature Spawns == Creature spawn data section is bounded by <code>CREATURES</code> and <code>END CREATURES</code> tags. Rain World only creates creature spawns when you enter a region for the first time on a save<!--, or after an excessive number of cycles has passed--><!--never heard of it before, may be bogus ~thalber-->. {|class="wikitable" !align="center" width="12%"| '''Lizards''' !align="center" width="25%"| '''Insects''' !align="center" width="13%"| '''Amphibians''' !align="center" width="18%"| '''Flying''' !align="center" width="16%"| '''Plants''' !align="center" width="12%"| '''Other''' |- |align="center"| Pink |align="center"| Spider |align="center"| Salamander |align="center"| CicadaA |align="center"| PoleMimic, Mimic* |align="center"| Scavenger |- |align="center"| Green |align="center"| Small Centipede |align="center"| Leech |align="center"| CicadaB |align="center"| Tentacle, TentaclePlant* |align="center"| Lantern Mouse, Mouse* |- |align="center"| Blue |align="center"| Centipede, Centi, Cent* |align="center"| SeaLeech |align="center"| Vulture |align="center"| |align="center"| Worm, Garbage Worm* |- |align="center"| Yellow |align="center"| Red Centipede, RedCenti, RedCentipede* |align="center"| JetFish, Jetfish* |align="center"| KingVulture, King Vulture* |align="center"| |align="center"| Miros, MirosBird* |- |align="center"| White |align="center"| DropBug, Dropbug, DropWig, Dropwig* |align="center"| Snail |align="center"| Needle, Needle Worm* |align="center"| |align="center"| Tube, TubeWorm* |- |align="center"| Black |align="center"| BigSpider |align="center"| Lev, Leviathan |align="center"| SmallNeedleWorm |align="center"| |align="center"| Bro, BroLongLegs* |- |align="center"| Cyan |align="center"| SpitterSpider |align="center"| |align="center"| Cicada** |align="center"| |align="center"| Daddy, DaddyLongLegs* |- |align="center"| Red |align="center"| EggBug, Eggbug* |align="center"| |align="center"| |align="center"| |align="center"| |} (*) Interchangeable names (**) Switches between CicadaA and CicadaB) <syntaxhighlight lang=""> //Creature spawns can be specific to a certain character. (0, 1) makes something appear for monk and survivor, (2) only for hunter (character filter)ROOM : PipeNumber-Creature-{optional flags}-Count </syntaxhighlight> <span id="examples-include-1"></span> === Examples === A single green lizard, spawning from pipe 2, on all difficulties. <syntaxhighlight lang=""> SU_A10 : 2-Green </syntaxhighlight> A single red lizard, spawning from pipe 3, on Hunter only. <syntaxhighlight lang=""> (2)SU_A10 : 3-Red </syntaxhighlight> A hoard of 5 yellow lizards spawning from pipe 1, on Monk only. <syntaxhighlight lang=""> (1)SU_A10 : 1-Yellow-5 </syntaxhighlight> A Daddy longlegs spawning from pipe 4, but only on easy and normal difficulties. <syntaxhighlight lang=""> (0,1)SU_A10 : 4-Daddy </syntaxhighlight> A very angry white lizard that spawns from pipe 3, on all difficulties. the “Mean” flag can be set from 0 to 1, and will change the enemy’s personality to pursue you aggressively depending on how high it is set. <syntaxhighlight lang=""> SU_A10 : 3-White-{Mean:0.9} </syntaxhighlight> Some enemies require a unique room known as OFFSCREEN. These enemies use special doors that are automatically added to your level to move between rooms. These include vultures, scavengers, leviathans, and miros birds. This example spawns two off screen vultures. <syntaxhighlight lang=""> OFFSCREEN : 0-Vulture-2 </syntaxhighlight> Enemy flags still apply to offscreen enemies. This will spawn a very aggressive KingVulture that will rarely leave the screen if it spots slugcat, but only on Hunter. <syntaxhighlight lang=""> (2)OFFSCREEN : 0-KingVulture-{Mean:1} </syntaxhighlight> <span id="important-quirks-to-creatures"></span> ==== Important quirks to creatures: ==== Enemies may be set to spawn from the same nest pipes. However, do not be surprised if they somehow kill each other offscreen very quickly if you do this. A daddy long legs may have no problems consuming an entire hoard of yellow lizards for example. Enemies will often drag you back to their home nest pipes, but may also choose other pipes they like, even in different rooms. During the end of a cycle, almost every enemy will rush to a nearby nest, if they spawned from it or not. Many creatures that would not intuitively appear to nest in pipes, likely does so, you just never reach them before they spawn in game, or their pipes are well hidden. A direct example of this, is that wandering daddy longlegs spawn from pipes, and return to their pipes before the end of a cycle. This includes the daddies inside Five Pebbles, which makes the area significantly easier once the cycle timer has counted down entirely. It is important to understand various enemy interactions to help you build a cohesive and believable ecosystem for an area. Sandbox mode can help you learn which creature is where on the food chain. As well as looking at the interactions of creatures in other regions. Some creatures have very specific requirements for rooms they inhabit. A very game breaking example, is that big spiders and spitting spiders require the ability to reach every wall in a room in some fashion. By pole, or by invisible ceilings out of the camera. If they cannot, the game will lag very badly due to the spider’s failed pathfinding. Some creatures have a heavier performance impact on the game then others. <!--Sandbox mode can help you learn these, as it will show a notice that “too many of this creature will impact performance” when you begin to place too many.--> <!-- the arena threshold seems somewhat arbitrary in present day--> An example is that more then 4 daddy long legs on screen will often lead to lag. Unfortunate development gets around this problem by using the “stuckDaddy” object, as these daddies do not run wandering path finding checks. All creature types can be configured using the dev tool’s map editor to prefer, avoid, stay or be forbidden inside certain rooms while wandering, using Attraction tool. These spawn entries are simply where they will be created from when the player first enters a region. <span id="the-lineage-system"></span> === The Lineage System === Enemy nests may also be configured to use the lineage system. After being killed, this allows a creature to roll a dice at the end of a cycle, and in a certain percent, respawn as its next entry in the lineage. Due to the format however, you cannot decide how many enemies can spawn from the pipe. So a green lizard cannot turn into a hoard of 3 yellow lizards. Only a single yellow lizard. Enemy flags, and difficulty filters still work however. The format is as follows: <syntaxhighlight lang=""> LINEAGE : ROOM : PIPE : STARTENEMY-PERCENT, NEXTENEMY-PERCENT, FINALENEMY-0 </syntaxhighlight> PERCENT is a value between 0 and 1, and is the percent chance that the enemy will move onto its next form. You may have as many forms as you need. However, it is important to ALWAYS mark the last enemy in the lineage with a 0 percent chance to move on. Rain World will crash the moment it attempts to move to the next enemy in a lineage from the last. === Examples === A green lizard that spawns from pipe 2, that turns into a blue, and then into a red. With a 5% chance each time. <syntaxhighlight lang=""> LINEAGE : SU_B08 : 2 : Green-0.05, Blue-0.05, Red-0 </syntaxhighlight> A poleplant, with a specific height of 10 blocks, and spawning from pipe 3. That has a 10% chance to turn into a monster kelp <syntaxhighlight lang=""> LINEAGE : SU_A02 : 3 : Mimic-{10}-0.1, TentaclePlant-0 </syntaxhighlight> A empty pipe 3, that has a 1% chance to turn into a monster kelp. <syntaxhighlight lang=""> LINEAGE : SU_B02 : 3 : NONE-0.01, TentaclePlant-0 </syntaxhighlight> Lineage applies to offscreen creatures, as well as difficulties! This example from chimney canopy has a 20% chance to turn a vulture into a king vulture after being killed, but only on normal difficulty. <syntaxhighlight lang=""> (0)LINEAGE : OFFSCREEN : 0 : Vulture-0.2, KingVulture-0 </syntaxhighlight> == Bat Migration Blockages == Bat migration blockages section is bounded by <code>BAT MIGRATION BLOCKAGES</code> and <code>END BAT MIGRATION BLOCKAGES</code> tags. These are used specifically to prevent bat flies from entering a room, or pathing through the region to rooms on the other side of it. These are rarely used. However the room directly after the tutorial area in outskirts is set to be one. The format is simply to list each room line by line between the two tags. There are no unique flags. For the example in Outskirts, bat flies cannot enter room SU_A22 because it is between the tags: <syntaxhighlight lang="">BAT MIGRATION BLOCKAGES SU_A22 END BAT MIGRATION BLOCKAGES </syntaxhighlight> [[Category:Content Mods]] 39ae83b15961b54dad52eb4eaa9b3605e9920f69 170 169 2022-08-07T20:30:57Z Thalber 3 wikitext text/x-wiki {{Cleanup}} [[File:regionFormat.png|thumb|right|alt=regionFormat|regionFormat]] This page describes worldfile format for RW regions. The world_XX.txt file is present in every region Rain World loads, and determines various room settings such as their pipe connections, the spawns of enemies, and specific flags like shelters and gates. NOTE: Creature spawns for the region are generated when you first enter it on a save. Changing room connections or creature spawns in WORLD_XX after that corrupts save data. '''Reset your saveslot or revert your save to before you entered to avoid bugs'''. == Comments == Worldfile format supports comments: if a line starts with double slash (<code>//</code>), it is ignored entirely. == Room Connections == Room connections section is bounded by <code>ROOMS</code> and <code>END ROOMS</code> tags. These control which pipe entrance leads to what room, and vice versa. Unique room flags that specify certain attributes about the room (such as if it is a shelter or a gate room) are set here as well. The format is as follows: <syntaxhighlight lang="">ROOM : door0, door1, door2, etc : FLAG </syntaxhighlight> === Examples === A standard room with two room-connecting pipes. These will form the bulk of your region. <syntaxhighlight lang="">TR_T07 : TR_T01, TR_P02 </syntaxhighlight> A standard room, with five doors. However, pipes 1, 2 and 3 have no connection. Each pipe inside a room has a specific number starting from 0. These can be viewed using the [[Dev Tools]]' map tab, or by entering the room with dev tools enabled and pressing M. <syntaxhighlight lang="">TR_W19 : TR_L05, DISCONNECTED, DISCONNECTED, DISCONNECTED, TR_W18 </syntaxhighlight> A shelter. These rooms will often be copied from other regions when you are first learning how to make a region. All vanilla save rooms have a single door. <syntaxhighlight lang="">TR_S01 : TR_P01 : SHELTER </syntaxhighlight> A region gate. Doors on the other side of the gate are set to DISCONNECTED. They will automatically be shown as connected doors at runtime. If you need to show a save room door specifically on the other side of the gate, you can use the ExitSymbolShelter object, in the dev tool’s object tab to change the door symbols as required. <syntaxhighlight lang="">GATE_SS_TR : DISCONNECTED, TR_L07 : GATE </syntaxhighlight> A swarm room allows batflies to spawn in the room, as long as the map contains bat nests. If the room has bat nests but is not marked as a swarm room, those nests will always be inactive. The dev tools map tab provides the options needed to control where they will migrate and rooms they will avoid. <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> A scavenger outpost. Use in conjunction with ScavengerOutpost placedObject to create a scavenger toll. <syntaxhighlight lang="">SU_C02 : SU_A45, SU_A07 : SCAVOUTPOST </syntaxhighlight> === Understanding door connections === [[File:regionFormatConnection.png|thumb|none|alt=regionFormatConnection|regionFormatConnection]] For a door to be properly connected, both ends must point to each other using valid doors. For this example, both rooms will have two doors. Door0 will be on the left, and door1 on the right. Door indices are decided specifically for your room, so be sure to check in game how your doors have been assigned by the [[Level Editor]]. The DT Map tab can also be used to see the links between doors. As in the picture to the right. Properly connected doors will show both lines pointing to the set door on the other end. Doors with incorrect links will point off to the bottom right <!--(A disconnected door will also do this,)--> <!--do fucking what--> and a door connected to another room, but that room has no door back (or lacks enough doors!) will point to the center of the room on the map tab page. <syntaxhighlight lang=""> RG_ROOM1 : DISCONNECTED, RG_ROOM2 </syntaxhighlight> <syntaxhighlight lang=""> RG_ROOM2: RG_ROOM1 </syntaxhighlight> Room1 will have its right hand door connected to Room2. Because of this, we need to use DISCONNECTED as a placeholder for its left hand door, door0. Then set door1 to connect to Room2 Room2 will connect to Room1 using door0. Due to this, we do not need to define the right hand door. It will assume it to be disconnected. === Room Tags === Room tags assign certain properties to rooms depending on what the tag is. Tags are assigned like <syntaxhighlight lang=""> [ROOM] : [CONNECTIONS] : [TAG] </syntaxhighlight> Example: <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> {| !width="18%"| '''<u>Tag</u>''' !width="81%"| '''<u>Function</u>''' |- | SHELTER | Makes the room a shelter. When there are multiple pipes in the room: the animated door is placed at the bottom right most pipe. |- | GATE | Makes the room a gate. Entrances on the other side of the gate are set to DISCONNECTED, and are shown automatically to be connected. |- | SWARMROOM | Allows batflies to be spawned from batfly hives. |- | PERF_HEAVY | Causes the room to be abstractized quicker when player is not inside, can reduce offscreen performance toll of very large rooms. |- | SCAVOUTPOST | Makes the room into a scavenger outpost. Scavs will spawn here and only let you pass if you have a pearl. The exact outpost location is set by the “ScavengerOutpost” devtools object. |- | SCAVTRADER | Spawns a scavenger merchant into the room. Will trade items with you. The merchant is controlled by the “TradeOutpost” devtools object. |} === Important quirks to rooms and doors === When setting up your region, be sure that you always use your region’s prefix to help each room have a unique name. If not, Rain World will treat repeated names as being other rooms, and even re-use rooms from other region folders entirely. If you don’t use your region prefix, changes made with devtools can also wind up getting saved to unexpected places. To avoid these problems, always prefix your room with its region code, and give them unique names. Multiple pipes in a room may all go to the same room. However, these will all act like a single pipe, and you will not be able to set the specific destination pipes. There are no cases in vanilla Rain World where multiple pipes in the current room lead to the same next room. They will all lead to separate rooms. For example, if you had four pipes leading from one room to another. you would need to create a minimum of three unique rooms for each of the other pipes to act as an interconnection. == Creature Spawns == Creature spawn data section is bounded by <code>CREATURES</code> and <code>END CREATURES</code> tags. Rain World only creates creature spawns when you enter a region for the first time on a save<!--, or after an excessive number of cycles has passed--><!--never heard of it before, may be bogus ~thalber-->. {|class="wikitable" !align="center" width="12%"| '''Lizards''' !align="center" width="25%"| '''Insects''' !align="center" width="13%"| '''Amphibians''' !align="center" width="18%"| '''Flying''' !align="center" width="16%"| '''Plants''' !align="center" width="12%"| '''Other''' |- |align="center"| Pink |align="center"| Spider |align="center"| Salamander |align="center"| CicadaA |align="center"| PoleMimic, Mimic* |align="center"| Scavenger |- |align="center"| Green |align="center"| Small Centipede |align="center"| Leech |align="center"| CicadaB |align="center"| Tentacle, TentaclePlant* |align="center"| Lantern Mouse, Mouse* |- |align="center"| Blue |align="center"| Centipede, Centi, Cent* |align="center"| SeaLeech |align="center"| Vulture |align="center"| |align="center"| Worm, Garbage Worm* |- |align="center"| Yellow |align="center"| Red Centipede, RedCenti, RedCentipede* |align="center"| JetFish, Jetfish* |align="center"| KingVulture, King Vulture* |align="center"| |align="center"| Miros, MirosBird* |- |align="center"| White |align="center"| DropBug, Dropbug, DropWig, Dropwig* |align="center"| Snail |align="center"| Needle, Needle Worm* |align="center"| |align="center"| Tube, TubeWorm* |- |align="center"| Black |align="center"| BigSpider |align="center"| Lev, Leviathan |align="center"| SmallNeedleWorm |align="center"| |align="center"| Bro, BroLongLegs* |- |align="center"| Cyan |align="center"| SpitterSpider |align="center"| |align="center"| Cicada** |align="center"| |align="center"| Daddy, DaddyLongLegs* |- |align="center"| Red |align="center"| EggBug, Eggbug* |align="center"| |align="center"| |align="center"| |align="center"| |} (*) Interchangeable names (**) Switches between CicadaA and CicadaB) <syntaxhighlight lang=""> //Creature spawns can be specific to a certain character. (0, 1) makes something appear for monk and survivor, (2) only for hunter (character filter)ROOM : PipeNumber-Creature-{optional flags}-Count </syntaxhighlight> === Examples === A single green lizard, spawning from pipe 2, on all difficulties. <syntaxhighlight lang=""> SU_A10 : 2-Green </syntaxhighlight> A single red lizard, spawning from pipe 3, on Hunter only. <syntaxhighlight lang=""> (2)SU_A10 : 3-Red </syntaxhighlight> A hoard of 5 yellow lizards spawning from pipe 1, on Monk only. <syntaxhighlight lang=""> (1)SU_A10 : 1-Yellow-5 </syntaxhighlight> A Daddy longlegs spawning from pipe 4, but only on easy and normal difficulties. <syntaxhighlight lang=""> (0,1)SU_A10 : 4-Daddy </syntaxhighlight> A very angry white lizard that spawns from pipe 3, on all difficulties. the “Mean” flag can be set from 0 to 1, and will change the enemy’s personality to pursue you aggressively depending on how high it is set. <syntaxhighlight lang=""> SU_A10 : 3-White-{Mean:0.9} </syntaxhighlight> Some enemies require a unique room known as OFFSCREEN. These enemies use special doors that are automatically added to your level to move between rooms. These include vultures, scavengers, leviathans, and miros birds. This example spawns two off screen vultures. <syntaxhighlight lang=""> OFFSCREEN : 0-Vulture-2 </syntaxhighlight> Enemy flags still apply to offscreen enemies. This will spawn a very aggressive KingVulture that will rarely leave the screen if it spots slugcat, but only on Hunter. <syntaxhighlight lang=""> (2)OFFSCREEN : 0-KingVulture-{Mean:1} </syntaxhighlight> <span id="important-quirks-to-creatures"></span> === Important quirks === Enemies may be set to spawn from the same nest pipes. However, do not be surprised if they somehow kill each other offscreen very quickly if you do this. A daddy long legs may have no problems consuming an entire hoard of yellow lizards for example. Enemies will often drag you back to their home nest pipes, but may also choose other pipes they like, even in different rooms. During the end of a cycle, almost every enemy will rush to a nearby nest, if they spawned from it or not. Many creatures that would not intuitively appear to nest in pipes, likely does so, you just never reach them before they spawn in game, or their pipes are well hidden. A direct example of this, is that wandering daddy longlegs spawn from pipes, and return to their pipes before the end of a cycle. This includes the daddies inside Five Pebbles, which makes the area significantly easier once the cycle timer has counted down entirely. It is important to understand various enemy interactions to help you build a cohesive and believable ecosystem for an area. Sandbox mode can help you learn which creature is where on the food chain. As well as looking at the interactions of creatures in other regions. Some creatures have very specific requirements for rooms they inhabit. A very game breaking example, is that big spiders and spitting spiders require the ability to reach every wall in a room in some fashion. By pole, or by invisible ceilings out of the camera. If they cannot, the game will lag very badly due to the spider’s failed pathfinding. Some creatures have a heavier performance impact on the game then others. <!--Sandbox mode can help you learn these, as it will show a notice that “too many of this creature will impact performance” when you begin to place too many.--> <!-- the arena threshold seems somewhat arbitrary in present day--> An example is that more then 4 daddy long legs on screen will often lead to lag. Unfortunate development gets around this problem by using the “stuckDaddy” object, as these daddies do not run wandering path finding checks. All creature types can be configured using the dev tool’s map editor to prefer, avoid, stay or be forbidden inside certain rooms while wandering, using Attraction tool. These spawn entries are simply where they will be created from when the player first enters a region. <span id="the-lineage-system"></span> === The Lineage System === Enemy nests may also be configured to use the lineage system. After being killed, this allows a creature to roll a dice at the end of a cycle, and in a certain percent, respawn as its next entry in the lineage. Due to the format however, you cannot decide how many enemies can spawn from the pipe. So a green lizard cannot turn into a hoard of 3 yellow lizards. Only a single yellow lizard. Enemy flags, and difficulty filters still work however. The format is as follows: <syntaxhighlight lang=""> LINEAGE : ROOM : PIPE : STARTENEMY-PERCENT, NEXTENEMY-PERCENT, FINALENEMY-0 </syntaxhighlight> PERCENT is a value between 0 and 1, and is the percent chance that the enemy will move onto its next form. You may have as many forms as you need. However, it is important to ALWAYS mark the last enemy in the lineage with a 0 percent chance to move on. Rain World will crash the moment it attempts to move to the next enemy in a lineage from the last. ==== Examples ==== A green lizard that spawns from pipe 2, that turns into a blue, and then into a red. With a 5% chance each time. <syntaxhighlight lang=""> LINEAGE : SU_B08 : 2 : Green-0.05, Blue-0.05, Red-0 </syntaxhighlight> A poleplant, with a specific height of 10 blocks, and spawning from pipe 3. That has a 10% chance to turn into a monster kelp <syntaxhighlight lang=""> LINEAGE : SU_A02 : 3 : Mimic-{10}-0.1, TentaclePlant-0 </syntaxhighlight> A empty pipe 3, that has a 1% chance to turn into a monster kelp. <syntaxhighlight lang=""> LINEAGE : SU_B02 : 3 : NONE-0.01, TentaclePlant-0 </syntaxhighlight> Lineage applies to offscreen creatures, as well as difficulties! This example from chimney canopy has a 20% chance to turn a vulture into a king vulture after being killed, but only on normal difficulty. <syntaxhighlight lang=""> (0)LINEAGE : OFFSCREEN : 0 : Vulture-0.2, KingVulture-0 </syntaxhighlight> == Bat Migration Blockages == Bat migration blockages section is bounded by <code>BAT MIGRATION BLOCKAGES</code> and <code>END BAT MIGRATION BLOCKAGES</code> tags. These are used specifically to prevent bat flies from entering a room, or pathing through the region to rooms on the other side of it. These are rarely used. However the room directly after the tutorial area in outskirts is set to be one. The format is simply to list each room line by line between the two tags. There are no unique flags. For the example in Outskirts, bat flies cannot enter room SU_A22 because it is between the tags: <syntaxhighlight lang="">BAT MIGRATION BLOCKAGES SU_A22 END BAT MIGRATION BLOCKAGES </syntaxhighlight> [[Category:Content Mods]] 4bc8b85ac0a4b21cfb7ce1d234d66bc6aa49365f 173 170 2022-08-10T16:39:42Z Thalber 3 fix table class wikitext text/x-wiki {{Cleanup}} [[File:regionFormat.png|thumb|right|alt=regionFormat|regionFormat]] This page describes worldfile format for RW regions. The world_XX.txt file is present in every region Rain World loads, and determines various room settings such as their pipe connections, the spawns of enemies, and specific flags like shelters and gates. NOTE: Creature spawns for the region are generated when you first enter it on a save. Changing room connections or creature spawns in WORLD_XX after that corrupts save data. '''Reset your saveslot or revert your save to before you entered to avoid bugs'''. == Comments == Worldfile format supports comments: if a line starts with double slash (<code>//</code>), it is ignored entirely. == Room Connections == Room connections section is bounded by <code>ROOMS</code> and <code>END ROOMS</code> tags. These control which pipe entrance leads to what room, and vice versa. Unique room flags that specify certain attributes about the room (such as if it is a shelter or a gate room) are set here as well. The format is as follows: <syntaxhighlight lang="">ROOM : door0, door1, door2, etc : FLAG </syntaxhighlight> === Examples === A standard room with two room-connecting pipes. These will form the bulk of your region. <syntaxhighlight lang="">TR_T07 : TR_T01, TR_P02 </syntaxhighlight> A standard room, with five doors. However, pipes 1, 2 and 3 have no connection. Each pipe inside a room has a specific number starting from 0. These can be viewed using the [[Dev Tools]]' map tab, or by entering the room with dev tools enabled and pressing M. <syntaxhighlight lang="">TR_W19 : TR_L05, DISCONNECTED, DISCONNECTED, DISCONNECTED, TR_W18 </syntaxhighlight> A shelter. These rooms will often be copied from other regions when you are first learning how to make a region. All vanilla save rooms have a single door. <syntaxhighlight lang="">TR_S01 : TR_P01 : SHELTER </syntaxhighlight> A region gate. Doors on the other side of the gate are set to DISCONNECTED. They will automatically be shown as connected doors at runtime. If you need to show a save room door specifically on the other side of the gate, you can use the ExitSymbolShelter object, in the dev tool’s object tab to change the door symbols as required. <syntaxhighlight lang="">GATE_SS_TR : DISCONNECTED, TR_L07 : GATE </syntaxhighlight> A swarm room allows batflies to spawn in the room, as long as the map contains bat nests. If the room has bat nests but is not marked as a swarm room, those nests will always be inactive. The dev tools map tab provides the options needed to control where they will migrate and rooms they will avoid. <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> A scavenger outpost. Use in conjunction with ScavengerOutpost placedObject to create a scavenger toll. <syntaxhighlight lang="">SU_C02 : SU_A45, SU_A07 : SCAVOUTPOST </syntaxhighlight> === Understanding door connections === [[File:regionFormatConnection.png|thumb|none|alt=regionFormatConnection|regionFormatConnection]] For a door to be properly connected, both ends must point to each other using valid doors. For this example, both rooms will have two doors. Door0 will be on the left, and door1 on the right. Door indices are decided specifically for your room, so be sure to check in game how your doors have been assigned by the [[Level Editor]]. The DT Map tab can also be used to see the links between doors. As in the picture to the right. Properly connected doors will show both lines pointing to the set door on the other end. Doors with incorrect links will point off to the bottom right <!--(A disconnected door will also do this,)--> <!--do fucking what--> and a door connected to another room, but that room has no door back (or lacks enough doors!) will point to the center of the room on the map tab page. <syntaxhighlight lang=""> RG_ROOM1 : DISCONNECTED, RG_ROOM2 </syntaxhighlight> <syntaxhighlight lang=""> RG_ROOM2: RG_ROOM1 </syntaxhighlight> Room1 will have its right hand door connected to Room2. Because of this, we need to use DISCONNECTED as a placeholder for its left hand door, door0. Then set door1 to connect to Room2 Room2 will connect to Room1 using door0. Due to this, we do not need to define the right hand door. It will assume it to be disconnected. === Room Tags === Room tags assign certain properties to rooms depending on what the tag is. Tags are assigned like <syntaxhighlight lang=""> [ROOM] : [CONNECTIONS] : [TAG] </syntaxhighlight> Example: <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> {|class="wikitable" !width="18%"| '''<u>Tag</u>''' !width="81%"| '''<u>Function</u>''' |- | SHELTER | Makes the room a shelter. When there are multiple pipes in the room: the animated door is placed at the bottom right most pipe. |- | GATE | Makes the room a gate. Entrances on the other side of the gate are set to DISCONNECTED, and are shown automatically to be connected. |- | SWARMROOM | Allows batflies to be spawned from batfly hives. |- | PERF_HEAVY | Causes the room to be abstractized quicker when player is not inside, can reduce offscreen performance toll of very large rooms. |- | SCAVOUTPOST | Makes the room into a scavenger outpost. Scavs will spawn here and only let you pass if you have a pearl. The exact outpost location is set by the “ScavengerOutpost” devtools object. |- | SCAVTRADER | Spawns a scavenger merchant into the room. Will trade items with you. The merchant is controlled by the “TradeOutpost” devtools object. |} === Important quirks to rooms and doors === When setting up your region, be sure that you always use your region’s prefix to help each room have a unique name. If not, Rain World will treat repeated names as being other rooms, and even re-use rooms from other region folders entirely. If you don’t use your region prefix, changes made with devtools can also wind up getting saved to unexpected places. To avoid these problems, always prefix your room with its region code, and give them unique names. Multiple pipes in a room may all go to the same room. However, these will all act like a single pipe, and you will not be able to set the specific destination pipes. There are no cases in vanilla Rain World where multiple pipes in the current room lead to the same next room. They will all lead to separate rooms. For example, if you had four pipes leading from one room to another. you would need to create a minimum of three unique rooms for each of the other pipes to act as an interconnection. == Creature Spawns == Creature spawn data section is bounded by <code>CREATURES</code> and <code>END CREATURES</code> tags. Rain World only creates creature spawns when you enter a region for the first time on a save<!--, or after an excessive number of cycles has passed--><!--never heard of it before, may be bogus ~thalber-->. {|class="wikitable" !align="center" width="12%"| '''Lizards''' !align="center" width="25%"| '''Insects''' !align="center" width="13%"| '''Amphibians''' !align="center" width="18%"| '''Flying''' !align="center" width="16%"| '''Plants''' !align="center" width="12%"| '''Other''' |- |align="center"| Pink |align="center"| Spider |align="center"| Salamander |align="center"| CicadaA |align="center"| PoleMimic, Mimic* |align="center"| Scavenger |- |align="center"| Green |align="center"| Small Centipede |align="center"| Leech |align="center"| CicadaB |align="center"| Tentacle, TentaclePlant* |align="center"| Lantern Mouse, Mouse* |- |align="center"| Blue |align="center"| Centipede, Centi, Cent* |align="center"| SeaLeech |align="center"| Vulture |align="center"| |align="center"| Worm, Garbage Worm* |- |align="center"| Yellow |align="center"| Red Centipede, RedCenti, RedCentipede* |align="center"| JetFish, Jetfish* |align="center"| KingVulture, King Vulture* |align="center"| |align="center"| Miros, MirosBird* |- |align="center"| White |align="center"| DropBug, Dropbug, DropWig, Dropwig* |align="center"| Snail |align="center"| Needle, Needle Worm* |align="center"| |align="center"| Tube, TubeWorm* |- |align="center"| Black |align="center"| BigSpider |align="center"| Lev, Leviathan |align="center"| SmallNeedleWorm |align="center"| |align="center"| Bro, BroLongLegs* |- |align="center"| Cyan |align="center"| SpitterSpider |align="center"| |align="center"| Cicada** |align="center"| |align="center"| Daddy, DaddyLongLegs* |- |align="center"| Red |align="center"| EggBug, Eggbug* |align="center"| |align="center"| |align="center"| |align="center"| |} (*) Interchangeable names (**) Switches between CicadaA and CicadaB) <syntaxhighlight lang=""> //Creature spawns can be specific to a certain character. (0, 1) makes something appear for monk and survivor, (2) only for hunter (character filter)ROOM : PipeNumber-Creature-{optional flags}-Count </syntaxhighlight> === Examples === A single green lizard, spawning from pipe 2, on all difficulties. <syntaxhighlight lang=""> SU_A10 : 2-Green </syntaxhighlight> A single red lizard, spawning from pipe 3, on Hunter only. <syntaxhighlight lang=""> (2)SU_A10 : 3-Red </syntaxhighlight> A hoard of 5 yellow lizards spawning from pipe 1, on Monk only. <syntaxhighlight lang=""> (1)SU_A10 : 1-Yellow-5 </syntaxhighlight> A Daddy longlegs spawning from pipe 4, but only on easy and normal difficulties. <syntaxhighlight lang=""> (0,1)SU_A10 : 4-Daddy </syntaxhighlight> A very angry white lizard that spawns from pipe 3, on all difficulties. the “Mean” flag can be set from 0 to 1, and will change the enemy’s personality to pursue you aggressively depending on how high it is set. <syntaxhighlight lang=""> SU_A10 : 3-White-{Mean:0.9} </syntaxhighlight> Some enemies require a unique room known as OFFSCREEN. These enemies use special doors that are automatically added to your level to move between rooms. These include vultures, scavengers, leviathans, and miros birds. This example spawns two off screen vultures. <syntaxhighlight lang=""> OFFSCREEN : 0-Vulture-2 </syntaxhighlight> Enemy flags still apply to offscreen enemies. This will spawn a very aggressive KingVulture that will rarely leave the screen if it spots slugcat, but only on Hunter. <syntaxhighlight lang=""> (2)OFFSCREEN : 0-KingVulture-{Mean:1} </syntaxhighlight> <span id="important-quirks-to-creatures"></span> === Important quirks === Enemies may be set to spawn from the same nest pipes. However, do not be surprised if they somehow kill each other offscreen very quickly if you do this. A daddy long legs may have no problems consuming an entire hoard of yellow lizards for example. Enemies will often drag you back to their home nest pipes, but may also choose other pipes they like, even in different rooms. During the end of a cycle, almost every enemy will rush to a nearby nest, if they spawned from it or not. Many creatures that would not intuitively appear to nest in pipes, likely does so, you just never reach them before they spawn in game, or their pipes are well hidden. A direct example of this, is that wandering daddy longlegs spawn from pipes, and return to their pipes before the end of a cycle. This includes the daddies inside Five Pebbles, which makes the area significantly easier once the cycle timer has counted down entirely. It is important to understand various enemy interactions to help you build a cohesive and believable ecosystem for an area. Sandbox mode can help you learn which creature is where on the food chain. As well as looking at the interactions of creatures in other regions. Some creatures have very specific requirements for rooms they inhabit. A very game breaking example, is that big spiders and spitting spiders require the ability to reach every wall in a room in some fashion. By pole, or by invisible ceilings out of the camera. If they cannot, the game will lag very badly due to the spider’s failed pathfinding. Some creatures have a heavier performance impact on the game then others. <!--Sandbox mode can help you learn these, as it will show a notice that “too many of this creature will impact performance” when you begin to place too many.--> <!-- the arena threshold seems somewhat arbitrary in present day--> An example is that more then 4 daddy long legs on screen will often lead to lag. Unfortunate development gets around this problem by using the “stuckDaddy” object, as these daddies do not run wandering path finding checks. All creature types can be configured using the dev tool’s map editor to prefer, avoid, stay or be forbidden inside certain rooms while wandering, using Attraction tool. These spawn entries are simply where they will be created from when the player first enters a region. <span id="the-lineage-system"></span> === The Lineage System === Enemy nests may also be configured to use the lineage system. After being killed, this allows a creature to roll a dice at the end of a cycle, and in a certain percent, respawn as its next entry in the lineage. Due to the format however, you cannot decide how many enemies can spawn from the pipe. So a green lizard cannot turn into a hoard of 3 yellow lizards. Only a single yellow lizard. Enemy flags, and difficulty filters still work however. The format is as follows: <syntaxhighlight lang=""> LINEAGE : ROOM : PIPE : STARTENEMY-PERCENT, NEXTENEMY-PERCENT, FINALENEMY-0 </syntaxhighlight> PERCENT is a value between 0 and 1, and is the percent chance that the enemy will move onto its next form. You may have as many forms as you need. However, it is important to ALWAYS mark the last enemy in the lineage with a 0 percent chance to move on. Rain World will crash the moment it attempts to move to the next enemy in a lineage from the last. ==== Examples ==== A green lizard that spawns from pipe 2, that turns into a blue, and then into a red. With a 5% chance each time. <syntaxhighlight lang=""> LINEAGE : SU_B08 : 2 : Green-0.05, Blue-0.05, Red-0 </syntaxhighlight> A poleplant, with a specific height of 10 blocks, and spawning from pipe 3. That has a 10% chance to turn into a monster kelp <syntaxhighlight lang=""> LINEAGE : SU_A02 : 3 : Mimic-{10}-0.1, TentaclePlant-0 </syntaxhighlight> A empty pipe 3, that has a 1% chance to turn into a monster kelp. <syntaxhighlight lang=""> LINEAGE : SU_B02 : 3 : NONE-0.01, TentaclePlant-0 </syntaxhighlight> Lineage applies to offscreen creatures, as well as difficulties! This example from chimney canopy has a 20% chance to turn a vulture into a king vulture after being killed, but only on normal difficulty. <syntaxhighlight lang=""> (0)LINEAGE : OFFSCREEN : 0 : Vulture-0.2, KingVulture-0 </syntaxhighlight> == Bat Migration Blockages == Bat migration blockages section is bounded by <code>BAT MIGRATION BLOCKAGES</code> and <code>END BAT MIGRATION BLOCKAGES</code> tags. These are used specifically to prevent bat flies from entering a room, or pathing through the region to rooms on the other side of it. These are rarely used. However the room directly after the tutorial area in outskirts is set to be one. The format is simply to list each room line by line between the two tags. There are no unique flags. For the example in Outskirts, bat flies cannot enter room SU_A22 because it is between the tags: <syntaxhighlight lang="">BAT MIGRATION BLOCKAGES SU_A22 END BAT MIGRATION BLOCKAGES </syntaxhighlight> [[Category:Content Mods]] 711a48e59e09710998fa8fe820b5b6c1bfc52ded Category:Content Mods 14 96 168 134 2022-08-07T19:31:36Z Thalber 3 wikitext text/x-wiki {{Cleanup}} Content mods are mods that consist primarily of asset files (e.g. sprite sheets, room files, audio etc). Content mods may contain new regions, sprite packs for player characters, arena level packs and so on. Content mods may depend on code mods in order to be loaded (such as [[CRS]]). They may be redistributed with supporting code libraries for additional features. For guidance on creating custom levels, see [[Level Editor]]. For region file structure, see [[World file format]]. f7abf4526d5eb8115e876412a7790d376f0ead30 ConfigMachine 0 115 174 2022-08-10T19:23:42Z Thalber 3 Port first section, may want to look into hiding large snippets by default wikitext text/x-wiki '''Configmachine''' is a dependency mod that allows other mods to easily create in-game config GUI. It's currently shipped with [[BepInEx]] installation. == Features == === OptionInterface === This is the most common method of adding config screen to your mod. ==== Registering ==== '''OptionalUI.OptionInterface''' is the base class for option interfaces. <syntaxhighlight lang="csharp"> public class MyOI : OptionInterface { public MyOI() : base (plugin: MyPlugin.instance) // Your BaseUnityPlugin instance. Examples assume you have a static singleton instance of your mod. { } } </syntaxhighlight> Now add <code>LoadOI</code> static method in your <code>BaseUnityPlugin</code> class that returns your OptionInterface. <syntaxhighlight lang="c#"> public static OptionInterface LoadOI() => return new MyOI(); //set return type to "object" if you want your mod to be loaded even if CM is not. In that case, you will need to handle CM's absence on your own. </syntaxhighlight> ==== Designing GUI ==== For designing your GUI, using [https://inkscape.org/ Inkscape] is strongly suggested. With Inkscape, create a file with 600 x 600 pixel resolution, then enable [View] - [Canvas Orientation] - [Flip Vertically]. (Alternatively, you can use any CAD program which has up and right as positive axis by default) <!--The image below is a diagram of <code>Colorfoot</code>’s first <code>OpTab</code>.--> [[File:Colorfoot-GUI.png|thumb|right|alt=Colorfoot's GUI as an example|Colorfoot's GUI as an example]] All UIelements have bottom-left <code>pos</code>ition and rectangular <code>size</code>. (Some have <code>fixedSize</code> which you can see from the summary of their constructors). Think every element like rectangles, and arrange them as you need. (Circular UIelements have <code>rad</code> instead; You can consider them as a square with 2 * rad for its dimensions) [[File:Colorfoot-GUI0.png|thumb|none|alt=Example GUI Positioning|Example GUI Positioning]] For <code>pos</code> parameters, use the relative coordinate from bottom-left from the canvas to your item. For <code>size</code> parameters, use their size in pixel. If you’re using Inkscape with [Flip Vertically] setting on, you can get those from their properties without any calculation. [[File:Colorfoot-Inkscape.png|thumb|none|alt=Example GUI Inkscape|Example GUI in Inkscape]] Here are some tips for designing GUI: * If you have many things to display, organise them with categories and use <code>OpRect</code> to surround them. * You don’t have to put everything in a single <code>OpTab</code>. If the canvas gets crowded, disperse your items for easier readability. * Try to avoid using smaller <code>OpScrollBox</code>s to store many things in one place even if that’s an option: The users cannot see everything in a single screen which reduces usability greatly. ==== Initialization ==== <code>OptionInterface.Initialize</code> is called in IntroRoll(for loading configuration) and ConfigMenu (for displaying to users). You can check whether Initialize is called in ConfigMenu or not with <code>OptionInterface.isOptionMenu</code>. It usually goes like this following example: <syntaxhighlight lang="csharp"> public override void Initialize() { base.Initialize(); // This should be called before everything else Tabs = new OpTab[2]; // you can have up to 20 tabs Tabs[0] = new OpTab("Main"); // Each OpTab is 600 x 600 pixel sized canvas Tabs[1] = new OpTab("Second") { color = Color.cyan }; // You can change its button and canvas colour too // After Initializing Tabs, create UIelements and add them to tabs } </syntaxhighlight> Now initialize <code>UIelement</code>s and add them to <code>OpTab</code> (or <code>OpScrollBox</code>). The Z-order (the order in which they’re drawn) of <code>UIelement</code>s is the order of constructors, ''not'' the order they’re added to <code>OpTab</code>. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpLabel(100f, 500f, "My Text") { description = "This is My Text" }); // Any UIelement can have description, which will be shown // at the bottom of the screen when the mouse cursor is over it </syntaxhighlight> <code>UIconfig</code>s are a subcategory of <code>UIelement</code> which have <code>key</code> and <code>value</code> for storing user input values, both of them get saved automatically by Config Machine. Their constructor accepts <code>key</code> and <code>defaultValue</code> on top of everything else. <code>key</code> must be unique for all elements in your OI unless they are cosmetic. Setting the key to empty or anything that starts with <code>_</code> (underbar) will turn it <code>cosmetic</code>, and the value won’t be saved. Cosmetic UIconfig is useful when you want to have provided <code>UIconfig</code> for UI purpose but not for an actual configurable. (Similarly, ModID that starts with <code>_</code> will be completely ignored by Config Machine) <syntaxhighlight lang="csharp"> OpCheckBox chkExample = new OpCheckBox(260f, 360f, "Example", true); Tabs[0].AddItems(chkExample, new OpLabel(260f, 390f, "Enable Example") { bumpBehav = chkExample.bumpBehav }); // BumpBehaviour is Config Machine's custom class that allows smoothly animated reaction with the input // Setting OpLabel's bumpBehav to other UIconfig/UItrigger's bumpBehav allows it to highlight with that element </syntaxhighlight> <code>UItrigger</code>s are the other subcategory of <code>UIelement</code>s which have <code>signal</code>s. When the user activates an <code>UItrigger</code> in some way, it will call the <code>Signal</code> function in OptionInterface which will be explained later. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpSimpleButton(new Vector2(400f, 200f), new Vector2(100f, 24f), "press", "Press Me")); </syntaxhighlight> ==== Update ==== <code>Update</code> function is called every frame when the game is in ConfigMenu, and this OptionInterface is currently active (The user has currently selected this mod from the list on left). This is useful to make reactive GUI, especially since each <code>UIconfig</code> instance can have only one value saved. The following example code uses cosmetic <code>OpRadioButtonGroup</code> to have four <code>OpColorPicker</code>s in a single spot. <syntaxhighlight lang="csharp"> private OpRadioButtonGroup rbgSelect; private int select; private OpColorPicker[] cpkPlayers; public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; select = 0; rbgSelect = new OpRadioButtonGroup("_", select); Tabs[0].AddItems(rbgSelect); rbgSelect.SetButtons(new OpRadioButton[] { new OpRadioButton(50f, 100f){ description = "The Survivor"}, new OpRadioButton(100f, 100f){ description = "The Monk"}, new OpRadioButton(150f, 100f){ description = "The Hunter"}, new OpRadioButton(200f, 100f){ description = "The Nightcat"} } ); OpColorPicker[] cpkPlayers = new OpColorPicker[4]; for (int i = 0; i < 4; i++) { Tabs[0].AddItems(new OpLabel(50f * i, 70f, rbgSelect.buttons[i].description) { bumpBehav = rbgSelect.buttons[i].bumpBehav }); cpkPlayers[i] = new OpColorPicker(new Vector2(100f, 300f), $"Color{i}", "FFFFFF"); cpkPlayers[i].Hide(); } cpkPlayers[select].Show(); Tabs[0].AddItems(cpkPlayers); } public override void Update(float dt) { base.Update(dt); // dt is deltaTime if (select != rbgSelect.valueInt) { for (int i = 0; i < cpkPlayers.Length; i++) { cpkPlayers[i].Hide(); } select = rbgSelect.valueInt; cpkPlayers[select].Show(); } } </syntaxhighlight> ==== ConfigOnChange ==== <code>ConfigOnChange</code> is called whenever <code>config</code> Dictionary is updated, mainly when Config Machine loads OptionInterfaces in IntroRoll, and when the user saves changes of configuration in ConfigMenu. Override this method to grab your configurable values. <code>config</code> Dictionary is where <code>UIconfig</code>’s value is stored. The following is an example of how to convert a string value to the corresponding type. <syntaxhighlight lang="csharp">public override void ConfigOnChange() { base.ConfigOnChange(); MyMod.config.myInt = int.Parse(config["keyInt"]); MyMod.config.myFloat = float.Parse(config["keyFloat"]); MyMod.config.myKey = OpKeyBinder.StringToKeyCode(config["keyKey"]); MyMod.config.myColor = OpColorPicker.HexToColor(config["keyColor"]); } </syntaxhighlight> ==== Signal ==== <code>Signal</code> is called when the user has interacted with <code>UItrigger</code>. Override this to have your OI to react. <syntaxhighlight lang="csharp"> public override void Signal(UItrigger trigger, string signal) { switch (signal) { case "reset": ConfigMenu.ResetCurrentConfig(); // This is the same as pressing Reset Config Button. break; } } </syntaxhighlight> [[Category:Dependencies]] [[Category:Code Mods]] c9bce3277ab18d3c5a1a2c997d3e960759efa3aa 175 174 2022-08-10T19:40:35Z Thalber 3 Add GOI section wikitext text/x-wiki '''Configmachine''' is a dependency mod that allows other mods to easily create in-game config GUI. It's currently shipped with [[BepInEx]] installation. == Features == === OptionInterface === This is the most common method of adding config screen to your mod. ==== Registering ==== '''OptionalUI.OptionInterface''' is the base class for option interfaces. <syntaxhighlight lang="csharp"> public class MyOI : OptionInterface { public MyOI() : base (plugin: MyPlugin.instance) // Your BaseUnityPlugin instance. Examples assume you have a static singleton instance of your mod. { } } </syntaxhighlight> Now add <code>LoadOI</code> static method in your <code>BaseUnityPlugin</code> class that returns your OptionInterface. <syntaxhighlight lang="c#"> public static OptionInterface LoadOI() => return new MyOI(); //set return type to "object" if you want your mod to be loaded even if CM is not. In that case, you will need to handle CM's absence on your own. </syntaxhighlight> ==== Designing GUI ==== For designing your GUI, using [https://inkscape.org/ Inkscape] is strongly suggested. With Inkscape, create a file with 600 x 600 pixel resolution, then enable [View] - [Canvas Orientation] - [Flip Vertically]. (Alternatively, you can use any CAD program which has up and right as positive axis by default) <!--The image below is a diagram of <code>Colorfoot</code>’s first <code>OpTab</code>.--> [[File:Colorfoot-GUI.png|thumb|right|alt=Colorfoot's GUI as an example|Colorfoot's GUI as an example]] All UIelements have bottom-left <code>pos</code>ition and rectangular <code>size</code>. (Some have <code>fixedSize</code> which you can see from the summary of their constructors). Think every element like rectangles, and arrange them as you need. (Circular UIelements have <code>rad</code> instead; You can consider them as a square with 2 * rad for its dimensions) [[File:Colorfoot-GUI0.png|thumb|none|alt=Example GUI Positioning|Example GUI Positioning]] For <code>pos</code> parameters, use the relative coordinate from bottom-left from the canvas to your item. For <code>size</code> parameters, use their size in pixel. If you’re using Inkscape with [Flip Vertically] setting on, you can get those from their properties without any calculation. [[File:Colorfoot-Inkscape.png|thumb|none|alt=Example GUI Inkscape|Example GUI in Inkscape]] Here are some tips for designing GUI: * If you have many things to display, organise them with categories and use <code>OpRect</code> to surround them. * You don’t have to put everything in a single <code>OpTab</code>. If the canvas gets crowded, disperse your items for easier readability. * Try to avoid using smaller <code>OpScrollBox</code>s to store many things in one place even if that’s an option: The users cannot see everything in a single screen which reduces usability greatly. ==== Initialization ==== <code>OptionInterface.Initialize</code> is called in IntroRoll(for loading configuration) and ConfigMenu (for displaying to users). You can check whether Initialize is called in ConfigMenu or not with <code>OptionInterface.isOptionMenu</code>. It usually goes like this following example: <syntaxhighlight lang="csharp"> public override void Initialize() { base.Initialize(); // This should be called before everything else Tabs = new OpTab[2]; // you can have up to 20 tabs Tabs[0] = new OpTab("Main"); // Each OpTab is 600 x 600 pixel sized canvas Tabs[1] = new OpTab("Second") { color = Color.cyan }; // You can change its button and canvas colour too // After Initializing Tabs, create UIelements and add them to tabs } </syntaxhighlight> Now initialize <code>UIelement</code>s and add them to <code>OpTab</code> (or <code>OpScrollBox</code>). The Z-order (the order in which they’re drawn) of <code>UIelement</code>s is the order of constructors, ''not'' the order they’re added to <code>OpTab</code>. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpLabel(100f, 500f, "My Text") { description = "This is My Text" }); // Any UIelement can have description, which will be shown // at the bottom of the screen when the mouse cursor is over it </syntaxhighlight> <code>UIconfig</code>s are a subcategory of <code>UIelement</code> which have <code>key</code> and <code>value</code> for storing user input values, both of them get saved automatically by Config Machine. Their constructor accepts <code>key</code> and <code>defaultValue</code> on top of everything else. <code>key</code> must be unique for all elements in your OI unless they are cosmetic. Setting the key to empty or anything that starts with <code>_</code> (underbar) will turn it <code>cosmetic</code>, and the value won’t be saved. Cosmetic UIconfig is useful when you want to have provided <code>UIconfig</code> for UI purpose but not for an actual configurable. (Similarly, ModID that starts with <code>_</code> will be completely ignored by Config Machine) <syntaxhighlight lang="csharp"> OpCheckBox chkExample = new OpCheckBox(260f, 360f, "Example", true); Tabs[0].AddItems(chkExample, new OpLabel(260f, 390f, "Enable Example") { bumpBehav = chkExample.bumpBehav }); // BumpBehaviour is Config Machine's custom class that allows smoothly animated reaction with the input // Setting OpLabel's bumpBehav to other UIconfig/UItrigger's bumpBehav allows it to highlight with that element </syntaxhighlight> <code>UItrigger</code>s are the other subcategory of <code>UIelement</code>s which have <code>signal</code>s. When the user activates an <code>UItrigger</code> in some way, it will call the <code>Signal</code> function in OptionInterface which will be explained later. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpSimpleButton(new Vector2(400f, 200f), new Vector2(100f, 24f), "press", "Press Me")); </syntaxhighlight> ==== Update ==== <code>Update</code> function is called every frame when the game is in ConfigMenu, and this OptionInterface is currently active (The user has currently selected this mod from the list on left). This is useful to make reactive GUI, especially since each <code>UIconfig</code> instance can have only one value saved. The following example code uses cosmetic <code>OpRadioButtonGroup</code> to have four <code>OpColorPicker</code>s in a single spot. <syntaxhighlight lang="csharp"> private OpRadioButtonGroup rbgSelect; private int select; private OpColorPicker[] cpkPlayers; public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; select = 0; rbgSelect = new OpRadioButtonGroup("_", select); Tabs[0].AddItems(rbgSelect); rbgSelect.SetButtons(new OpRadioButton[] { new OpRadioButton(50f, 100f){ description = "The Survivor"}, new OpRadioButton(100f, 100f){ description = "The Monk"}, new OpRadioButton(150f, 100f){ description = "The Hunter"}, new OpRadioButton(200f, 100f){ description = "The Nightcat"} } ); OpColorPicker[] cpkPlayers = new OpColorPicker[4]; for (int i = 0; i < 4; i++) { Tabs[0].AddItems(new OpLabel(50f * i, 70f, rbgSelect.buttons[i].description) { bumpBehav = rbgSelect.buttons[i].bumpBehav }); cpkPlayers[i] = new OpColorPicker(new Vector2(100f, 300f), $"Color{i}", "FFFFFF"); cpkPlayers[i].Hide(); } cpkPlayers[select].Show(); Tabs[0].AddItems(cpkPlayers); } public override void Update(float dt) { base.Update(dt); // dt is deltaTime if (select != rbgSelect.valueInt) { for (int i = 0; i < cpkPlayers.Length; i++) { cpkPlayers[i].Hide(); } select = rbgSelect.valueInt; cpkPlayers[select].Show(); } } </syntaxhighlight> ==== ConfigOnChange ==== <code>ConfigOnChange</code> is called whenever <code>config</code> Dictionary is updated, mainly when Config Machine loads OptionInterfaces in IntroRoll, and when the user saves changes of configuration in ConfigMenu. Override this method to grab your configurable values. <code>config</code> Dictionary is where <code>UIconfig</code>’s value is stored. The following is an example of how to convert a string value to the corresponding type. <syntaxhighlight lang="csharp">public override void ConfigOnChange() { base.ConfigOnChange(); MyMod.config.myInt = int.Parse(config["keyInt"]); MyMod.config.myFloat = float.Parse(config["keyFloat"]); MyMod.config.myKey = OpKeyBinder.StringToKeyCode(config["keyKey"]); MyMod.config.myColor = OpColorPicker.HexToColor(config["keyColor"]); } </syntaxhighlight> ==== Signal ==== <code>Signal</code> is called when the user has interacted with <code>UItrigger</code>. Override this to have your OI to react. <syntaxhighlight lang="csharp"> public override void Signal(UItrigger trigger, string signal) { switch (signal) { case "reset": ConfigMenu.ResetCurrentConfig(); // This is the same as pressing Reset Config Button. break; } } </syntaxhighlight> === Generated OIs === <code>GeneratedOI</code> is a child class of <code>OptionInterface</code> that helps generating fixed-format GUI with less effort. <span id="displaying-basic-profile"></span> ==== Displaying Basic Profile ==== Simply inheriting <code>GeneratedOI</code> instead of <code>OptionInterface</code> works. This does make your mod dependent to Config Machine, and Config Machine generates GUI to display the basic information of your mod without this dependency. So this is only useful when you’re using OptionInterface for other features, like its Translation API. <syntaxhighlight lang="c#"> public class MyOI : GeneratedOI { private const string desc = "Changes this thing and that thing"; public MyOI() : base(plugin: MyPlugin.instance, desc) { transFile = "MyPlugin.Translation.txt"; } } </syntaxhighlight> The code above would generate a GUI like the following image: [[File:GeneratedOI-sample.png|thumb|none|alt=GeneratedOI Sample|GeneratedOI Sample]] You can also use its static method <code>AddBasicProfile</code> for basic profiles on top of the canvas. This also has an overload that accepts <code>OpScrollBox</code> instead of <code>OpTab</code>, if you have <code>OpScrollBox</code> replacing <code>OpTab</code>. <syntaxhighlight lang="c#"> public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; GeneratedOI.AddBasicProfile(Tabs[0], rwMod); Tabs[0].AddItems(new OpCheckBox(100f, 350f, "EnableStuff", false) { description = "Enables this stuff" }); } </syntaxhighlight> ==== BepInEx.Configuration ==== If you don't provide an OptionInterface, BepInEx can generate a simple config screen from your [[BepInPlugins|plugin]]'s config bindings (see <code>BepInEx.Configuration</code>). If this happens, CM will not create a separate file to store your config values. This method has upsides and downsides. * You don’t need to reference Config Machine in your project, and this doesn’t create a dependency for Config Machine. * The users can configure the plugin by opening the cfg file in Notepad outside the game. * However, you do not have control on detailed GUI design. First, we need <code>ConfigEntry</code> which you can bind to the <code>Config</code> property of <code>BaseUnityPlugin</code>. Consult [https://docs.bepinex.dev/articles/dev_guide/plugin_tutorial/4_configuration.html BepInEx Documentation] for farther detail. <syntaxhighlight lang="c#"> public static ConfigEntry<string> cfgText; public static ConfigEntry<bool> cfgCheck; void Awake() { cfgText = Config.Bind( "General", // section: defines which OpTab this will go "My Setting", // key: the name of setting "Hello, world!" // defaultValue "This is a description. It does things." // The description will be shown the right side of UIconfig // When you hover your mouse on UIconfig, // the first sentence will be displayed at the bottom of the screen ); cfgCheck = Config.Bind("General", "My Other Setting", true, "Another description is this."); } </syntaxhighlight> To access those settings, use <code>Value</code>. <syntaxhighlight lang="c#"> if (cfgCheck.Value) { Logger.LogMessage(cfgText.Value); } </syntaxhighlight> == Acceptable Types == As of Config Machine <code>v1.5.1</code>, it accepts the following types and uses provided UIconfig. (Height is the pixel height that how much this ConfigEntry would use. And each entry get 20 pixeled gaps in between) {|class="wikitable" !align="right" width="23%"| type !align="center" width="29%"| UIconfig !align="right" width="23%"| Height !width="23%"| Note |- |align="right"| bool |align="center"| OpCheckBox |align="right"| 60 | |- |align="right"| byte |align="center"| OpSliderSubtle |align="right"| 90 | Range: [0, 20] |- |align="right"| uint |align="center"| OpSlider |align="right"| 90 | Range: [0, 100] |- |align="right"| int |align="center"| OpTextBox |align="right"| 60 | Accepts: Int |- |align="right"| float |align="center"| OpTextBox |align="right"| 60 | Accepts: Float |- |align="right"| string(Hex) |align="center"| OpColorPicker |align="right"| 170 | When defaultValue is Hex |- |align="right"| string |align="center"| OpTextBox |align="right"| 60 | When defaultValue is not Hex; Accepts: ASCII |- |align="right"| KeyCode |align="center"| OpKeyBinder |align="right"| 100 | |- |align="right"| enumType |align="center"| OpResourceSelector |align="right"| 60 | |- |align="right"| default |align="center"| N/A |align="right"| | Will warn the user that this plugin has ConfigEntry that’s not supported by Config Machine |} [[Category:Dependencies]] [[Category:Code Mods]] b5ec9ecf3bd7cba43c93e48f5a2f057924121370 176 175 2022-08-10T19:51:05Z Thalber 3 Add translation section wikitext text/x-wiki '''Configmachine''' is a dependency mod that allows other mods to easily create in-game config GUI. It's currently shipped with [[BepInEx]] installation. == Features == === OptionInterface === This is the most common method of adding config screen to your mod. ==== Registering ==== '''OptionalUI.OptionInterface''' is the base class for option interfaces. <syntaxhighlight lang="csharp"> public class MyOI : OptionInterface { public MyOI() : base (plugin: MyPlugin.instance) // Your BaseUnityPlugin instance. Examples assume you have a static singleton instance of your mod. { } } </syntaxhighlight> Now add <code>LoadOI</code> static method in your <code>BaseUnityPlugin</code> class that returns your OptionInterface. <syntaxhighlight lang="c#"> public static OptionInterface LoadOI() => return new MyOI(); //set return type to "object" if you want your mod to be loaded even if CM is not. In that case, you will need to handle CM's absence on your own. </syntaxhighlight> ==== Designing GUI ==== For designing your GUI, using [https://inkscape.org/ Inkscape] is strongly suggested. With Inkscape, create a file with 600 x 600 pixel resolution, then enable [View] - [Canvas Orientation] - [Flip Vertically]. (Alternatively, you can use any CAD program which has up and right as positive axis by default) <!--The image below is a diagram of <code>Colorfoot</code>’s first <code>OpTab</code>.--> [[File:Colorfoot-GUI.png|thumb|right|alt=Colorfoot's GUI as an example|Colorfoot's GUI as an example]] All UIelements have bottom-left <code>pos</code>ition and rectangular <code>size</code>. (Some have <code>fixedSize</code> which you can see from the summary of their constructors). Think every element like rectangles, and arrange them as you need. (Circular UIelements have <code>rad</code> instead; You can consider them as a square with 2 * rad for its dimensions) [[File:Colorfoot-GUI0.png|thumb|none|alt=Example GUI Positioning|Example GUI Positioning]] For <code>pos</code> parameters, use the relative coordinate from bottom-left from the canvas to your item. For <code>size</code> parameters, use their size in pixel. If you’re using Inkscape with [Flip Vertically] setting on, you can get those from their properties without any calculation. [[File:Colorfoot-Inkscape.png|thumb|none|alt=Example GUI Inkscape|Example GUI in Inkscape]] Here are some tips for designing GUI: * If you have many things to display, organise them with categories and use <code>OpRect</code> to surround them. * You don’t have to put everything in a single <code>OpTab</code>. If the canvas gets crowded, disperse your items for easier readability. * Try to avoid using smaller <code>OpScrollBox</code>s to store many things in one place even if that’s an option: The users cannot see everything in a single screen which reduces usability greatly. ==== Initialization ==== <code>OptionInterface.Initialize</code> is called in IntroRoll(for loading configuration) and ConfigMenu (for displaying to users). You can check whether Initialize is called in ConfigMenu or not with <code>OptionInterface.isOptionMenu</code>. It usually goes like this following example: <syntaxhighlight lang="csharp"> public override void Initialize() { base.Initialize(); // This should be called before everything else Tabs = new OpTab[2]; // you can have up to 20 tabs Tabs[0] = new OpTab("Main"); // Each OpTab is 600 x 600 pixel sized canvas Tabs[1] = new OpTab("Second") { color = Color.cyan }; // You can change its button and canvas colour too // After Initializing Tabs, create UIelements and add them to tabs } </syntaxhighlight> Now initialize <code>UIelement</code>s and add them to <code>OpTab</code> (or <code>OpScrollBox</code>). The Z-order (the order in which they’re drawn) of <code>UIelement</code>s is the order of constructors, ''not'' the order they’re added to <code>OpTab</code>. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpLabel(100f, 500f, "My Text") { description = "This is My Text" }); // Any UIelement can have description, which will be shown // at the bottom of the screen when the mouse cursor is over it </syntaxhighlight> <code>UIconfig</code>s are a subcategory of <code>UIelement</code> which have <code>key</code> and <code>value</code> for storing user input values, both of them get saved automatically by Config Machine. Their constructor accepts <code>key</code> and <code>defaultValue</code> on top of everything else. <code>key</code> must be unique for all elements in your OI unless they are cosmetic. Setting the key to empty or anything that starts with <code>_</code> (underbar) will turn it <code>cosmetic</code>, and the value won’t be saved. Cosmetic UIconfig is useful when you want to have provided <code>UIconfig</code> for UI purpose but not for an actual configurable. (Similarly, ModID that starts with <code>_</code> will be completely ignored by Config Machine) <syntaxhighlight lang="csharp"> OpCheckBox chkExample = new OpCheckBox(260f, 360f, "Example", true); Tabs[0].AddItems(chkExample, new OpLabel(260f, 390f, "Enable Example") { bumpBehav = chkExample.bumpBehav }); // BumpBehaviour is Config Machine's custom class that allows smoothly animated reaction with the input // Setting OpLabel's bumpBehav to other UIconfig/UItrigger's bumpBehav allows it to highlight with that element </syntaxhighlight> <code>UItrigger</code>s are the other subcategory of <code>UIelement</code>s which have <code>signal</code>s. When the user activates an <code>UItrigger</code> in some way, it will call the <code>Signal</code> function in OptionInterface which will be explained later. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpSimpleButton(new Vector2(400f, 200f), new Vector2(100f, 24f), "press", "Press Me")); </syntaxhighlight> ==== Update ==== <code>Update</code> function is called every frame when the game is in ConfigMenu, and this OptionInterface is currently active (The user has currently selected this mod from the list on left). This is useful to make reactive GUI, especially since each <code>UIconfig</code> instance can have only one value saved. The following example code uses cosmetic <code>OpRadioButtonGroup</code> to have four <code>OpColorPicker</code>s in a single spot. <syntaxhighlight lang="csharp"> private OpRadioButtonGroup rbgSelect; private int select; private OpColorPicker[] cpkPlayers; public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; select = 0; rbgSelect = new OpRadioButtonGroup("_", select); Tabs[0].AddItems(rbgSelect); rbgSelect.SetButtons(new OpRadioButton[] { new OpRadioButton(50f, 100f){ description = "The Survivor"}, new OpRadioButton(100f, 100f){ description = "The Monk"}, new OpRadioButton(150f, 100f){ description = "The Hunter"}, new OpRadioButton(200f, 100f){ description = "The Nightcat"} } ); OpColorPicker[] cpkPlayers = new OpColorPicker[4]; for (int i = 0; i < 4; i++) { Tabs[0].AddItems(new OpLabel(50f * i, 70f, rbgSelect.buttons[i].description) { bumpBehav = rbgSelect.buttons[i].bumpBehav }); cpkPlayers[i] = new OpColorPicker(new Vector2(100f, 300f), $"Color{i}", "FFFFFF"); cpkPlayers[i].Hide(); } cpkPlayers[select].Show(); Tabs[0].AddItems(cpkPlayers); } public override void Update(float dt) { base.Update(dt); // dt is deltaTime if (select != rbgSelect.valueInt) { for (int i = 0; i < cpkPlayers.Length; i++) { cpkPlayers[i].Hide(); } select = rbgSelect.valueInt; cpkPlayers[select].Show(); } } </syntaxhighlight> ==== ConfigOnChange ==== <code>ConfigOnChange</code> is called whenever <code>config</code> Dictionary is updated, mainly when Config Machine loads OptionInterfaces in IntroRoll, and when the user saves changes of configuration in ConfigMenu. Override this method to grab your configurable values. <code>config</code> Dictionary is where <code>UIconfig</code>’s value is stored. The following is an example of how to convert a string value to the corresponding type. <syntaxhighlight lang="csharp">public override void ConfigOnChange() { base.ConfigOnChange(); MyMod.config.myInt = int.Parse(config["keyInt"]); MyMod.config.myFloat = float.Parse(config["keyFloat"]); MyMod.config.myKey = OpKeyBinder.StringToKeyCode(config["keyKey"]); MyMod.config.myColor = OpColorPicker.HexToColor(config["keyColor"]); } </syntaxhighlight> ==== Signal ==== <code>Signal</code> is called when the user has interacted with <code>UItrigger</code>. Override this to have your OI to react. <syntaxhighlight lang="csharp"> public override void Signal(UItrigger trigger, string signal) { switch (signal) { case "reset": ConfigMenu.ResetCurrentConfig(); // This is the same as pressing Reset Config Button. break; } } </syntaxhighlight> === Generated OIs === <code>GeneratedOI</code> is a child class of <code>OptionInterface</code> that helps generating fixed-format GUI with less effort. <span id="displaying-basic-profile"></span> ==== Displaying Basic Profile ==== Simply inheriting <code>GeneratedOI</code> instead of <code>OptionInterface</code> works. This does make your mod dependent to Config Machine, and Config Machine generates GUI to display the basic information of your mod without this dependency. So this is only useful when you’re using OptionInterface for other features, like its Translation API. <syntaxhighlight lang="c#"> public class MyOI : GeneratedOI { private const string desc = "Changes this thing and that thing"; public MyOI() : base(plugin: MyPlugin.instance, desc) { transFile = "MyPlugin.Translation.txt"; } } </syntaxhighlight> The code above would generate a GUI like the following image: [[File:GeneratedOI-sample.png|thumb|none|alt=GeneratedOI Sample|GeneratedOI Sample]] You can also use its static method <code>AddBasicProfile</code> for basic profiles on top of the canvas. This also has an overload that accepts <code>OpScrollBox</code> instead of <code>OpTab</code>, if you have <code>OpScrollBox</code> replacing <code>OpTab</code>. <syntaxhighlight lang="c#"> public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; GeneratedOI.AddBasicProfile(Tabs[0], rwMod); Tabs[0].AddItems(new OpCheckBox(100f, 350f, "EnableStuff", false) { description = "Enables this stuff" }); } </syntaxhighlight> ==== BepInEx.Configuration ==== If you don't provide an OptionInterface, BepInEx can generate a simple config screen from your [[BepInPlugins|plugin]]'s config bindings (see <code>BepInEx.Configuration</code>). If this happens, CM will not create a separate file to store your config values. This method has upsides and downsides. * You don’t need to reference Config Machine in your project, and this doesn’t create a dependency for Config Machine. * The users can configure the plugin by opening the cfg file in Notepad outside the game. * However, you do not have control on detailed GUI design. First, we need <code>ConfigEntry</code> which you can bind to the <code>Config</code> property of <code>BaseUnityPlugin</code>. Consult [https://docs.bepinex.dev/articles/dev_guide/plugin_tutorial/4_configuration.html BepInEx Documentation] for farther detail. <syntaxhighlight lang="c#"> public static ConfigEntry<string> cfgText; public static ConfigEntry<bool> cfgCheck; void Awake() { cfgText = Config.Bind( "General", // section: defines which OpTab this will go "My Setting", // key: the name of setting "Hello, world!" // defaultValue "This is a description. It does things." // The description will be shown the right side of UIconfig // When you hover your mouse on UIconfig, // the first sentence will be displayed at the bottom of the screen ); cfgCheck = Config.Bind("General", "My Other Setting", true, "Another description is this."); } </syntaxhighlight> To access those settings, use <code>Value</code>. <syntaxhighlight lang="c#"> if (cfgCheck.Value) { Logger.LogMessage(cfgText.Value); } </syntaxhighlight> === Translation Support === While you can support translation for your mod on your own, Config Machine also offers translation solution. ==== Preparation ==== <code>OptionInterface</code> has a method called <code>Translate</code>, and when it's initially called, it will load specified (<code>transFile</code>) txt file from your assembly and make Dictionary depending on Rain World's language setting. In <code>BaseUnityPlugin.LoadOI</code> method, store the <code>OptionInterface</code> instance in somewhere before returning it. <syntaxhighlight lang="c#"> public static MyOI oi; public static MyOI LoadOI() { oi = new MyOI(); return oi; } </syntaxhighlight> Then make a static method that calls the translation method. <syntaxhighlight lang="c#">public static string Translate(string orig) { if (oi != null) { return oi.Translate(orig); } return orig; } </syntaxhighlight> Now when you need to translate something, you can pass your string through this method. ==== Writing Translation txt ==== Create a txt file that contains translation, too. Add txt file to your project, ''make sure'' that its encoding is <code>UTF-8</code>, then set it to be [Embedded Resources] for its compile setting. Then, in the constructor of your OptionInterface, set <code>transFile</code> to that resource name. If you have not put it in any folder, it's usually <code>&lt;ProjectName&gt;.&lt;TxtFileName&gt;.txt</code>, but you might get it wrong. If it's wrong when <code>OptionInterface.Translate</code> is initially called, Config Machine will log all the resources in your assembly in exceptionLog.txt so you can copy from it. <syntaxhighlight lang="c#">public MyOI() : base(plugin: MyPlugin.instance) { this.transFile = "MyPlugin.Translation.txt"; // if you do not know the resource name, just call Translate. // ConfigMachine will log all the resources in your assembly in exceptionLog.txt. } </syntaxhighlight> The format of the translation txt file for Config Machine is quite primitive. First, you add a keyword, then <code>|</code> for language separator, then language ID (<code>eng, ita, ger, spa, por, kor, jap, rus)</code>), <code>$</code> for another separator, then translation. If there is no translation, the translator will return the keyword, unless there is a translation for <code>eng</code>. (In that case, English "translation" will be used as default translation) The following is formatting example for txt file. <pre> // If the first two characters are '//', this line will be ignored. Nightcat Horn Colour|kor$¹ã°í¾çÀÌ »Ô »ö±ò // If you have variables, avoid using partial sentences. Not every language has the same subject-verb-object order. Press &lt;ThrowKey&gt; to stab.|kor$&lt;ThrowKey&gt; ¹öưÀ» ´­·¯ Â±â. // When translating the shorter-phrase, the translation might be sensitive with context, but English one does not. Duplicate key causes error(You can check exceptionLog.txt for duplicates), so you can set 'eng' translation for these cases. Property_as of possession|eng$Property|kor$¼ÒÀ¯¹° Property_as of quality|eng$Property|kor$¼Ó¼º // For line-breaks, use \n. (In code, it¡¯d be \\n) Each line represents a phrase, so you can¡¯t use actual line-break in a single chunk. LINE\nBREAK|kor$ÁÙ\n¹Ù²Þ</pre> ==== Running Translation ==== And here are some examples in code. Yes, running every text through the <code>Translate</code> method is tedious, but this is usually how it's done in Rain World or many other games. Make sure to check your mod in another language to confirm you haven’t missed any item. <syntaxhighlight lang="c#"> labelCpkrRadio.text = MyPlugin.Translate("Nightcat Horn Colour"); instance.room.game.cameras[0].hud.textPrompt.AddMessage(MyPlugin.Translate("Press <ThrowKey> to stab.").Replace("<ThrowKey>", k.ToString())); // k is variable in this example. labelLineBreak.text = MyPlugin.Translate("LINE\\nBREAK"); </syntaxhighlight> <!== These aren't the part of tutorial but more of tips. This does not just apply for making Rain World mods but to general, whenever you're making something that supports translation. * When you have variables in your sentence, do not use partial phrases and Frankenstein it later with <code>string.Concat</code>. Not every language has the same grammar order of subject-verb-object as English. * Leave credits to the translators, since you¡¯re most likely getting volunteers from them. This is both good for showing gratitude to the translators and keeping the quality of the translation. The lack of credits equals a lack of responsibility. * Do not use machine translation. That usually hurts the user experience rather than enhancing it. --> == Acceptable Types == As of Config Machine <code>v1.5.1</code>, it accepts the following types and uses provided UIconfig. (Height is the pixel height that how much this ConfigEntry would use. And each entry get 20 pixeled gaps in between) {|class="wikitable" !align="right" width="23%"| type !align="center" width="29%"| UIconfig !align="right" width="23%"| Height !width="23%"| Note |- |align="right"| bool |align="center"| OpCheckBox |align="right"| 60 | |- |align="right"| byte |align="center"| OpSliderSubtle |align="right"| 90 | Range: [0, 20] |- |align="right"| uint |align="center"| OpSlider |align="right"| 90 | Range: [0, 100] |- |align="right"| int |align="center"| OpTextBox |align="right"| 60 | Accepts: Int |- |align="right"| float |align="center"| OpTextBox |align="right"| 60 | Accepts: Float |- |align="right"| string(Hex) |align="center"| OpColorPicker |align="right"| 170 | When defaultValue is Hex |- |align="right"| string |align="center"| OpTextBox |align="right"| 60 | When defaultValue is not Hex; Accepts: ASCII |- |align="right"| KeyCode |align="center"| OpKeyBinder |align="right"| 100 | |- |align="right"| enumType |align="center"| OpResourceSelector |align="right"| 60 | |- |align="right"| default |align="center"| N/A |align="right"| | Will warn the user that this plugin has ConfigEntry that’s not supported by Config Machine |} [[Category:Dependencies]] [[Category:Code Mods]] 058b4a5a04ce05914a7a0161fe3bc81656b1506f 177 176 2022-08-10T19:53:14Z Thalber 3 wikitext text/x-wiki '''Configmachine''' is a dependency mod that allows other mods to easily create in-game config GUI. It's currently shipped with [[BepInEx]] installation. == Features == === OptionInterface === This is the most common method of adding config screen to your mod. ==== Registering ==== '''OptionalUI.OptionInterface''' is the base class for option interfaces. <syntaxhighlight lang="csharp"> public class MyOI : OptionInterface { public MyOI() : base (plugin: MyPlugin.instance) // Your BaseUnityPlugin instance. Examples assume you have a static singleton instance of your mod. { } } </syntaxhighlight> Now add <code>LoadOI</code> static method in your <code>BaseUnityPlugin</code> class that returns your OptionInterface. <syntaxhighlight lang="c#"> public static OptionInterface LoadOI() => return new MyOI(); //set return type to "object" if you want your mod to be loaded even if CM is not. In that case, you will need to handle CM's absence on your own. </syntaxhighlight> ==== Designing GUI ==== For designing your GUI, using [https://inkscape.org/ Inkscape] is strongly suggested. With Inkscape, create a file with 600 x 600 pixel resolution, then enable [View] - [Canvas Orientation] - [Flip Vertically]. (Alternatively, you can use any CAD program which has up and right as positive axis by default) <!--The image below is a diagram of <code>Colorfoot</code>’s first <code>OpTab</code>.--> [[File:Colorfoot-GUI.png|thumb|right|alt=Colorfoot's GUI as an example|Colorfoot's GUI as an example]] All UIelements have bottom-left <code>pos</code>ition and rectangular <code>size</code>. (Some have <code>fixedSize</code> which you can see from the summary of their constructors). Think every element like rectangles, and arrange them as you need. (Circular UIelements have <code>rad</code> instead; You can consider them as a square with 2 * rad for its dimensions) [[File:Colorfoot-GUI0.png|thumb|none|alt=Example GUI Positioning|Example GUI Positioning]] For <code>pos</code> parameters, use the relative coordinate from bottom-left from the canvas to your item. For <code>size</code> parameters, use their size in pixel. If you’re using Inkscape with [Flip Vertically] setting on, you can get those from their properties without any calculation. [[File:Colorfoot-Inkscape.png|thumb|none|alt=Example GUI Inkscape|Example GUI in Inkscape]] Here are some tips for designing GUI: * If you have many things to display, organise them with categories and use <code>OpRect</code> to surround them. * You don’t have to put everything in a single <code>OpTab</code>. If the canvas gets crowded, disperse your items for easier readability. * Try to avoid using smaller <code>OpScrollBox</code>s to store many things in one place even if that’s an option: The users cannot see everything in a single screen which reduces usability greatly. ==== Initialization ==== <code>OptionInterface.Initialize</code> is called in IntroRoll(for loading configuration) and ConfigMenu (for displaying to users). You can check whether Initialize is called in ConfigMenu or not with <code>OptionInterface.isOptionMenu</code>. It usually goes like this following example: <syntaxhighlight lang="csharp"> public override void Initialize() { base.Initialize(); // This should be called before everything else Tabs = new OpTab[2]; // you can have up to 20 tabs Tabs[0] = new OpTab("Main"); // Each OpTab is 600 x 600 pixel sized canvas Tabs[1] = new OpTab("Second") { color = Color.cyan }; // You can change its button and canvas colour too // After Initializing Tabs, create UIelements and add them to tabs } </syntaxhighlight> Now initialize <code>UIelement</code>s and add them to <code>OpTab</code> (or <code>OpScrollBox</code>). The Z-order (the order in which they’re drawn) of <code>UIelement</code>s is the order of constructors, ''not'' the order they’re added to <code>OpTab</code>. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpLabel(100f, 500f, "My Text") { description = "This is My Text" }); // Any UIelement can have description, which will be shown // at the bottom of the screen when the mouse cursor is over it </syntaxhighlight> <code>UIconfig</code>s are a subcategory of <code>UIelement</code> which have <code>key</code> and <code>value</code> for storing user input values, both of them get saved automatically by Config Machine. Their constructor accepts <code>key</code> and <code>defaultValue</code> on top of everything else. <code>key</code> must be unique for all elements in your OI unless they are cosmetic. Setting the key to empty or anything that starts with <code>_</code> (underbar) will turn it <code>cosmetic</code>, and the value won’t be saved. Cosmetic UIconfig is useful when you want to have provided <code>UIconfig</code> for UI purpose but not for an actual configurable. (Similarly, ModID that starts with <code>_</code> will be completely ignored by Config Machine) <syntaxhighlight lang="csharp"> OpCheckBox chkExample = new OpCheckBox(260f, 360f, "Example", true); Tabs[0].AddItems(chkExample, new OpLabel(260f, 390f, "Enable Example") { bumpBehav = chkExample.bumpBehav }); // BumpBehaviour is Config Machine's custom class that allows smoothly animated reaction with the input // Setting OpLabel's bumpBehav to other UIconfig/UItrigger's bumpBehav allows it to highlight with that element </syntaxhighlight> <code>UItrigger</code>s are the other subcategory of <code>UIelement</code>s which have <code>signal</code>s. When the user activates an <code>UItrigger</code> in some way, it will call the <code>Signal</code> function in OptionInterface which will be explained later. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpSimpleButton(new Vector2(400f, 200f), new Vector2(100f, 24f), "press", "Press Me")); </syntaxhighlight> ==== Update ==== <code>Update</code> function is called every frame when the game is in ConfigMenu, and this OptionInterface is currently active (The user has currently selected this mod from the list on left). This is useful to make reactive GUI, especially since each <code>UIconfig</code> instance can have only one value saved. The following example code uses cosmetic <code>OpRadioButtonGroup</code> to have four <code>OpColorPicker</code>s in a single spot. <syntaxhighlight lang="csharp"> private OpRadioButtonGroup rbgSelect; private int select; private OpColorPicker[] cpkPlayers; public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; select = 0; rbgSelect = new OpRadioButtonGroup("_", select); Tabs[0].AddItems(rbgSelect); rbgSelect.SetButtons(new OpRadioButton[] { new OpRadioButton(50f, 100f){ description = "The Survivor"}, new OpRadioButton(100f, 100f){ description = "The Monk"}, new OpRadioButton(150f, 100f){ description = "The Hunter"}, new OpRadioButton(200f, 100f){ description = "The Nightcat"} } ); OpColorPicker[] cpkPlayers = new OpColorPicker[4]; for (int i = 0; i < 4; i++) { Tabs[0].AddItems(new OpLabel(50f * i, 70f, rbgSelect.buttons[i].description) { bumpBehav = rbgSelect.buttons[i].bumpBehav }); cpkPlayers[i] = new OpColorPicker(new Vector2(100f, 300f), $"Color{i}", "FFFFFF"); cpkPlayers[i].Hide(); } cpkPlayers[select].Show(); Tabs[0].AddItems(cpkPlayers); } public override void Update(float dt) { base.Update(dt); // dt is deltaTime if (select != rbgSelect.valueInt) { for (int i = 0; i < cpkPlayers.Length; i++) { cpkPlayers[i].Hide(); } select = rbgSelect.valueInt; cpkPlayers[select].Show(); } } </syntaxhighlight> ==== ConfigOnChange ==== <code>ConfigOnChange</code> is called whenever <code>config</code> Dictionary is updated, mainly when Config Machine loads OptionInterfaces in IntroRoll, and when the user saves changes of configuration in ConfigMenu. Override this method to grab your configurable values. <code>config</code> Dictionary is where <code>UIconfig</code>’s value is stored. The following is an example of how to convert a string value to the corresponding type. <syntaxhighlight lang="csharp">public override void ConfigOnChange() { base.ConfigOnChange(); MyMod.config.myInt = int.Parse(config["keyInt"]); MyMod.config.myFloat = float.Parse(config["keyFloat"]); MyMod.config.myKey = OpKeyBinder.StringToKeyCode(config["keyKey"]); MyMod.config.myColor = OpColorPicker.HexToColor(config["keyColor"]); } </syntaxhighlight> ==== Signal ==== <code>Signal</code> is called when the user has interacted with <code>UItrigger</code>. Override this to have your OI to react. <syntaxhighlight lang="csharp"> public override void Signal(UItrigger trigger, string signal) { switch (signal) { case "reset": ConfigMenu.ResetCurrentConfig(); // This is the same as pressing Reset Config Button. break; } } </syntaxhighlight> === Generated OIs === <code>GeneratedOI</code> is a child class of <code>OptionInterface</code> that helps generating fixed-format GUI with less effort. <span id="displaying-basic-profile"></span> ==== Displaying Basic Profile ==== Simply inheriting <code>GeneratedOI</code> instead of <code>OptionInterface</code> works. This does make your mod dependent to Config Machine, and Config Machine generates GUI to display the basic information of your mod without this dependency. So this is only useful when you’re using OptionInterface for other features, like its Translation API. <syntaxhighlight lang="c#"> public class MyOI : GeneratedOI { private const string desc = "Changes this thing and that thing"; public MyOI() : base(plugin: MyPlugin.instance, desc) { transFile = "MyPlugin.Translation.txt"; } } </syntaxhighlight> The code above would generate a GUI like the following image: [[File:GeneratedOI-sample.png|thumb|none|alt=GeneratedOI Sample|GeneratedOI Sample]] You can also use its static method <code>AddBasicProfile</code> for basic profiles on top of the canvas. This also has an overload that accepts <code>OpScrollBox</code> instead of <code>OpTab</code>, if you have <code>OpScrollBox</code> replacing <code>OpTab</code>. <syntaxhighlight lang="c#"> public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; GeneratedOI.AddBasicProfile(Tabs[0], rwMod); Tabs[0].AddItems(new OpCheckBox(100f, 350f, "EnableStuff", false) { description = "Enables this stuff" }); } </syntaxhighlight> ==== BepInEx.Configuration ==== If you don't provide an OptionInterface, BepInEx can generate a simple config screen from your [[BepInPlugins|plugin]]'s config bindings (see <code>BepInEx.Configuration</code>). If this happens, CM will not create a separate file to store your config values. This method has upsides and downsides. * You don’t need to reference Config Machine in your project, and this doesn’t create a dependency for Config Machine. * The users can configure the plugin by opening the cfg file in Notepad outside the game. * However, you do not have control on detailed GUI design. First, we need <code>ConfigEntry</code> which you can bind to the <code>Config</code> property of <code>BaseUnityPlugin</code>. Consult [https://docs.bepinex.dev/articles/dev_guide/plugin_tutorial/4_configuration.html BepInEx Documentation] for farther detail. <syntaxhighlight lang="c#"> public static ConfigEntry<string> cfgText; public static ConfigEntry<bool> cfgCheck; void Awake() { cfgText = Config.Bind( "General", // section: defines which OpTab this will go "My Setting", // key: the name of setting "Hello, world!" // defaultValue "This is a description. It does things." // The description will be shown the right side of UIconfig // When you hover your mouse on UIconfig, // the first sentence will be displayed at the bottom of the screen ); cfgCheck = Config.Bind("General", "My Other Setting", true, "Another description is this."); } </syntaxhighlight> To access those settings, use <code>Value</code>. <syntaxhighlight lang="c#"> if (cfgCheck.Value) { Logger.LogMessage(cfgText.Value); } </syntaxhighlight> === Translation Support === While you can support translation for your mod on your own, Config Machine also offers translation solution. ==== Preparation ==== <code>OptionInterface</code> has a method called <code>Translate</code>, and when it's initially called, it will load specified (<code>transFile</code>) txt file from your assembly and make Dictionary depending on Rain World's language setting. In <code>BaseUnityPlugin.LoadOI</code> method, store the <code>OptionInterface</code> instance in somewhere before returning it. <syntaxhighlight lang="c#"> public static MyOI oi; public static MyOI LoadOI() { oi = new MyOI(); return oi; } </syntaxhighlight> Then make a static method that calls the translation method. <syntaxhighlight lang="c#">public static string Translate(string orig) { if (oi != null) { return oi.Translate(orig); } return orig; } </syntaxhighlight> Now when you need to translate something, you can pass your string through this method. ==== Writing Translation txt ==== Create a txt file that contains translation, too. Add txt file to your project, ''make sure'' that its encoding is <code>UTF-8</code>, then set it to be [Embedded Resources] for its compile setting. Then, in the constructor of your OptionInterface, set <code>transFile</code> to that resource name. If you have not put it in any folder, it's usually <code>&lt;ProjectName&gt;.&lt;TxtFileName&gt;.txt</code>, but you might get it wrong. If it's wrong when <code>OptionInterface.Translate</code> is initially called, Config Machine will log all the resources in your assembly in exceptionLog.txt so you can copy from it. <syntaxhighlight lang="c#">public MyOI() : base(plugin: MyPlugin.instance) { this.transFile = "MyPlugin.Translation.txt"; // if you do not know the resource name, just call Translate. // ConfigMachine will log all the resources in your assembly in exceptionLog.txt. } </syntaxhighlight> The format of the translation txt file for Config Machine is quite primitive. First, you add a keyword, then <code>|</code> for language separator, then language ID (<code>eng, ita, ger, spa, por, kor, jap, rus)</code>), <code>$</code> for another separator, then translation. If there is no translation, the translator will return the keyword, unless there is a translation for <code>eng</code>. (In that case, English "translation" will be used as default translation) The following is formatting example for txt file. <pre> // If the first two characters are '//', this line will be ignored. Nightcat Horn Colour|kor$¹ã°í¾çÀÌ »Ô »ö±ò // If you have variables, avoid using partial sentences. Not every language has the same subject-verb-object order. Press &lt;ThrowKey&gt; to stab.|kor$&lt;ThrowKey&gt; ¹öưÀ» ´­·¯ Â±â. // When translating the shorter-phrase, the translation might be sensitive with context, but English one does not. Duplicate key causes error(You can check exceptionLog.txt for duplicates), so you can set 'eng' translation for these cases. Property_as of possession|eng$Property|kor$¼ÒÀ¯¹° Property_as of quality|eng$Property|kor$¼Ó¼º // For line-breaks, use \n. (In code, it¡¯d be \\n) Each line represents a phrase, so you can¡¯t use actual line-break in a single chunk. LINE\nBREAK|kor$ÁÙ\n¹Ù²Þ</pre> ==== Running Translation ==== And here are some examples in code. Yes, running every text through the <code>Translate</code> method is tedious, but this is usually how it's done in Rain World or many other games. Make sure to check your mod in another language to confirm you haven’t missed any item. <syntaxhighlight lang="c#"> labelCpkrRadio.text = MyPlugin.Translate("Nightcat Horn Colour"); instance.room.game.cameras[0].hud.textPrompt.AddMessage(MyPlugin.Translate("Press <ThrowKey> to stab.").Replace("<ThrowKey>", k.ToString())); // k is variable in this example. labelLineBreak.text = MyPlugin.Translate("LINE\\nBREAK"); </syntaxhighlight> <!-- These aren't the part of tutorial but more of tips. This does not just apply for making Rain World mods but to general, whenever you're making something that supports translation. * When you have variables in your sentence, do not use partial phrases and Frankenstein it later with <code>string.Concat</code>. Not every language has the same grammar order of subject-verb-object as English. * Leave credits to the translators, since you¡¯re most likely getting volunteers from them. This is both good for showing gratitude to the translators and keeping the quality of the translation. The lack of credits equals a lack of responsibility. * Do not use machine translation. That usually hurts the user experience rather than enhancing it. --> == Acceptable Types == As of Config Machine <code>v1.5.1</code>, it accepts the following types and uses provided UIconfig. (Height is the pixel height that how much this ConfigEntry would use. And each entry get 20 pixeled gaps in between) {|class="wikitable" !align="right" width="23%"| type !align="center" width="29%"| UIconfig !align="right" width="23%"| Height !width="23%"| Note |- |align="right"| bool |align="center"| OpCheckBox |align="right"| 60 | |- |align="right"| byte |align="center"| OpSliderSubtle |align="right"| 90 | Range: [0, 20] |- |align="right"| uint |align="center"| OpSlider |align="right"| 90 | Range: [0, 100] |- |align="right"| int |align="center"| OpTextBox |align="right"| 60 | Accepts: Int |- |align="right"| float |align="center"| OpTextBox |align="right"| 60 | Accepts: Float |- |align="right"| string(Hex) |align="center"| OpColorPicker |align="right"| 170 | When defaultValue is Hex |- |align="right"| string |align="center"| OpTextBox |align="right"| 60 | When defaultValue is not Hex; Accepts: ASCII |- |align="right"| KeyCode |align="center"| OpKeyBinder |align="right"| 100 | |- |align="right"| enumType |align="center"| OpResourceSelector |align="right"| 60 | |- |align="right"| default |align="center"| N/A |align="right"| | Will warn the user that this plugin has ConfigEntry that’s not supported by Config Machine |} [[Category:Dependencies]] [[Category:Code Mods]] a11454259bfa9db668c6e9d1cafac1012e715a09 178 177 2022-08-10T19:54:21Z Thalber 3 wikitext text/x-wiki {{Cleanup}} '''Configmachine''' is a dependency mod that allows other mods to easily create in-game config GUI. It's currently shipped with [[BepInEx]] installation. == Features == === OptionInterface === This is the most common method of adding config screen to your mod. ==== Registering ==== '''OptionalUI.OptionInterface''' is the base class for option interfaces. <syntaxhighlight lang="csharp"> public class MyOI : OptionInterface { public MyOI() : base (plugin: MyPlugin.instance) // Your BaseUnityPlugin instance. Examples assume you have a static singleton instance of your mod. { } } </syntaxhighlight> Now add <code>LoadOI</code> static method in your <code>BaseUnityPlugin</code> class that returns your OptionInterface. <syntaxhighlight lang="c#"> public static OptionInterface LoadOI() => return new MyOI(); //set return type to "object" if you want your mod to be loaded even if CM is not. In that case, you will need to handle CM's absence on your own. </syntaxhighlight> ==== Designing GUI ==== For designing your GUI, using [https://inkscape.org/ Inkscape] is strongly suggested. With Inkscape, create a file with 600 x 600 pixel resolution, then enable [View] - [Canvas Orientation] - [Flip Vertically]. (Alternatively, you can use any CAD program which has up and right as positive axis by default) <!--The image below is a diagram of <code>Colorfoot</code>’s first <code>OpTab</code>.--> [[File:Colorfoot-GUI.png|thumb|right|alt=Colorfoot's GUI as an example|Colorfoot's GUI as an example]] All UIelements have bottom-left <code>pos</code>ition and rectangular <code>size</code>. (Some have <code>fixedSize</code> which you can see from the summary of their constructors). Think every element like rectangles, and arrange them as you need. (Circular UIelements have <code>rad</code> instead; You can consider them as a square with 2 * rad for its dimensions) [[File:Colorfoot-GUI0.png|thumb|none|alt=Example GUI Positioning|Example GUI Positioning]] For <code>pos</code> parameters, use the relative coordinate from bottom-left from the canvas to your item. For <code>size</code> parameters, use their size in pixel. If you’re using Inkscape with [Flip Vertically] setting on, you can get those from their properties without any calculation. [[File:Colorfoot-Inkscape.png|thumb|none|alt=Example GUI Inkscape|Example GUI in Inkscape]] Here are some tips for designing GUI: * If you have many things to display, organise them with categories and use <code>OpRect</code> to surround them. * You don’t have to put everything in a single <code>OpTab</code>. If the canvas gets crowded, disperse your items for easier readability. * Try to avoid using smaller <code>OpScrollBox</code>s to store many things in one place even if that’s an option: The users cannot see everything in a single screen which reduces usability greatly. ==== Initialization ==== <code>OptionInterface.Initialize</code> is called in IntroRoll(for loading configuration) and ConfigMenu (for displaying to users). You can check whether Initialize is called in ConfigMenu or not with <code>OptionInterface.isOptionMenu</code>. It usually goes like this following example: <syntaxhighlight lang="csharp"> public override void Initialize() { base.Initialize(); // This should be called before everything else Tabs = new OpTab[2]; // you can have up to 20 tabs Tabs[0] = new OpTab("Main"); // Each OpTab is 600 x 600 pixel sized canvas Tabs[1] = new OpTab("Second") { color = Color.cyan }; // You can change its button and canvas colour too // After Initializing Tabs, create UIelements and add them to tabs } </syntaxhighlight> Now initialize <code>UIelement</code>s and add them to <code>OpTab</code> (or <code>OpScrollBox</code>). The Z-order (the order in which they’re drawn) of <code>UIelement</code>s is the order of constructors, ''not'' the order they’re added to <code>OpTab</code>. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpLabel(100f, 500f, "My Text") { description = "This is My Text" }); // Any UIelement can have description, which will be shown // at the bottom of the screen when the mouse cursor is over it </syntaxhighlight> <code>UIconfig</code>s are a subcategory of <code>UIelement</code> which have <code>key</code> and <code>value</code> for storing user input values, both of them get saved automatically by Config Machine. Their constructor accepts <code>key</code> and <code>defaultValue</code> on top of everything else. <code>key</code> must be unique for all elements in your OI unless they are cosmetic. Setting the key to empty or anything that starts with <code>_</code> (underbar) will turn it <code>cosmetic</code>, and the value won’t be saved. Cosmetic UIconfig is useful when you want to have provided <code>UIconfig</code> for UI purpose but not for an actual configurable. (Similarly, ModID that starts with <code>_</code> will be completely ignored by Config Machine) <syntaxhighlight lang="csharp"> OpCheckBox chkExample = new OpCheckBox(260f, 360f, "Example", true); Tabs[0].AddItems(chkExample, new OpLabel(260f, 390f, "Enable Example") { bumpBehav = chkExample.bumpBehav }); // BumpBehaviour is Config Machine's custom class that allows smoothly animated reaction with the input // Setting OpLabel's bumpBehav to other UIconfig/UItrigger's bumpBehav allows it to highlight with that element </syntaxhighlight> <code>UItrigger</code>s are the other subcategory of <code>UIelement</code>s which have <code>signal</code>s. When the user activates an <code>UItrigger</code> in some way, it will call the <code>Signal</code> function in OptionInterface which will be explained later. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpSimpleButton(new Vector2(400f, 200f), new Vector2(100f, 24f), "press", "Press Me")); </syntaxhighlight> ==== Update ==== <code>Update</code> function is called every frame when the game is in ConfigMenu, and this OptionInterface is currently active (The user has currently selected this mod from the list on left). This is useful to make reactive GUI, especially since each <code>UIconfig</code> instance can have only one value saved. The following example code uses cosmetic <code>OpRadioButtonGroup</code> to have four <code>OpColorPicker</code>s in a single spot. <syntaxhighlight lang="csharp"> private OpRadioButtonGroup rbgSelect; private int select; private OpColorPicker[] cpkPlayers; public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; select = 0; rbgSelect = new OpRadioButtonGroup("_", select); Tabs[0].AddItems(rbgSelect); rbgSelect.SetButtons(new OpRadioButton[] { new OpRadioButton(50f, 100f){ description = "The Survivor"}, new OpRadioButton(100f, 100f){ description = "The Monk"}, new OpRadioButton(150f, 100f){ description = "The Hunter"}, new OpRadioButton(200f, 100f){ description = "The Nightcat"} } ); OpColorPicker[] cpkPlayers = new OpColorPicker[4]; for (int i = 0; i < 4; i++) { Tabs[0].AddItems(new OpLabel(50f * i, 70f, rbgSelect.buttons[i].description) { bumpBehav = rbgSelect.buttons[i].bumpBehav }); cpkPlayers[i] = new OpColorPicker(new Vector2(100f, 300f), $"Color{i}", "FFFFFF"); cpkPlayers[i].Hide(); } cpkPlayers[select].Show(); Tabs[0].AddItems(cpkPlayers); } public override void Update(float dt) { base.Update(dt); // dt is deltaTime if (select != rbgSelect.valueInt) { for (int i = 0; i < cpkPlayers.Length; i++) { cpkPlayers[i].Hide(); } select = rbgSelect.valueInt; cpkPlayers[select].Show(); } } </syntaxhighlight> ==== ConfigOnChange ==== <code>ConfigOnChange</code> is called whenever <code>config</code> Dictionary is updated, mainly when Config Machine loads OptionInterfaces in IntroRoll, and when the user saves changes of configuration in ConfigMenu. Override this method to grab your configurable values. <code>config</code> Dictionary is where <code>UIconfig</code>’s value is stored. The following is an example of how to convert a string value to the corresponding type. <syntaxhighlight lang="csharp">public override void ConfigOnChange() { base.ConfigOnChange(); MyMod.config.myInt = int.Parse(config["keyInt"]); MyMod.config.myFloat = float.Parse(config["keyFloat"]); MyMod.config.myKey = OpKeyBinder.StringToKeyCode(config["keyKey"]); MyMod.config.myColor = OpColorPicker.HexToColor(config["keyColor"]); } </syntaxhighlight> ==== Signal ==== <code>Signal</code> is called when the user has interacted with <code>UItrigger</code>. Override this to have your OI to react. <syntaxhighlight lang="csharp"> public override void Signal(UItrigger trigger, string signal) { switch (signal) { case "reset": ConfigMenu.ResetCurrentConfig(); // This is the same as pressing Reset Config Button. break; } } </syntaxhighlight> === Generated OIs === <code>GeneratedOI</code> is a child class of <code>OptionInterface</code> that helps generating fixed-format GUI with less effort. <span id="displaying-basic-profile"></span> ==== Displaying Basic Profile ==== Simply inheriting <code>GeneratedOI</code> instead of <code>OptionInterface</code> works. This does make your mod dependent to Config Machine, and Config Machine generates GUI to display the basic information of your mod without this dependency. So this is only useful when you’re using OptionInterface for other features, like its Translation API. <syntaxhighlight lang="c#"> public class MyOI : GeneratedOI { private const string desc = "Changes this thing and that thing"; public MyOI() : base(plugin: MyPlugin.instance, desc) { transFile = "MyPlugin.Translation.txt"; } } </syntaxhighlight> The code above would generate a GUI like the following image: [[File:GeneratedOI-sample.png|thumb|none|alt=GeneratedOI Sample|GeneratedOI Sample]] You can also use its static method <code>AddBasicProfile</code> for basic profiles on top of the canvas. This also has an overload that accepts <code>OpScrollBox</code> instead of <code>OpTab</code>, if you have <code>OpScrollBox</code> replacing <code>OpTab</code>. <syntaxhighlight lang="c#"> public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; GeneratedOI.AddBasicProfile(Tabs[0], rwMod); Tabs[0].AddItems(new OpCheckBox(100f, 350f, "EnableStuff", false) { description = "Enables this stuff" }); } </syntaxhighlight> ==== BepInEx.Configuration ==== If you don't provide an OptionInterface, BepInEx can generate a simple config screen from your [[BepInPlugins|plugin]]'s config bindings (see <code>BepInEx.Configuration</code>). If this happens, CM will not create a separate file to store your config values. This method has upsides and downsides. * You don’t need to reference Config Machine in your project, and this doesn’t create a dependency for Config Machine. * The users can configure the plugin by opening the cfg file in Notepad outside the game. * However, you do not have control on detailed GUI design. First, we need <code>ConfigEntry</code> which you can bind to the <code>Config</code> property of <code>BaseUnityPlugin</code>. Consult [https://docs.bepinex.dev/articles/dev_guide/plugin_tutorial/4_configuration.html BepInEx Documentation] for farther detail. <syntaxhighlight lang="c#"> public static ConfigEntry<string> cfgText; public static ConfigEntry<bool> cfgCheck; void Awake() { cfgText = Config.Bind( "General", // section: defines which OpTab this will go "My Setting", // key: the name of setting "Hello, world!" // defaultValue "This is a description. It does things." // The description will be shown the right side of UIconfig // When you hover your mouse on UIconfig, // the first sentence will be displayed at the bottom of the screen ); cfgCheck = Config.Bind("General", "My Other Setting", true, "Another description is this."); } </syntaxhighlight> To access those settings, use <code>Value</code>. <syntaxhighlight lang="c#"> if (cfgCheck.Value) { Logger.LogMessage(cfgText.Value); } </syntaxhighlight> === Translation Support === While you can support translation for your mod on your own, Config Machine also offers translation solution. ==== Preparation ==== <code>OptionInterface</code> has a method called <code>Translate</code>, and when it's initially called, it will load specified (<code>transFile</code>) txt file from your assembly and make Dictionary depending on Rain World's language setting. In <code>BaseUnityPlugin.LoadOI</code> method, store the <code>OptionInterface</code> instance in somewhere before returning it. <syntaxhighlight lang="c#"> public static MyOI oi; public static MyOI LoadOI() { oi = new MyOI(); return oi; } </syntaxhighlight> Then make a static method that calls the translation method. <syntaxhighlight lang="c#">public static string Translate(string orig) { if (oi != null) { return oi.Translate(orig); } return orig; } </syntaxhighlight> Now when you need to translate something, you can pass your string through this method. ==== Writing Translation txt ==== Create a txt file that contains translation, too. Add txt file to your project, ''make sure'' that its encoding is <code>UTF-8</code>, then set it to be [Embedded Resources] for its compile setting. Then, in the constructor of your OptionInterface, set <code>transFile</code> to that resource name. If you have not put it in any folder, it's usually <code>&lt;ProjectName&gt;.&lt;TxtFileName&gt;.txt</code>, but you might get it wrong. If it's wrong when <code>OptionInterface.Translate</code> is initially called, Config Machine will log all the resources in your assembly in exceptionLog.txt so you can copy from it. <syntaxhighlight lang="c#">public MyOI() : base(plugin: MyPlugin.instance) { this.transFile = "MyPlugin.Translation.txt"; // if you do not know the resource name, just call Translate. // ConfigMachine will log all the resources in your assembly in exceptionLog.txt. } </syntaxhighlight> The format of the translation txt file for Config Machine is quite primitive. First, you add a keyword, then <code>|</code> for language separator, then language ID (<code>eng, ita, ger, spa, por, kor, jap, rus)</code>), <code>$</code> for another separator, then translation. If there is no translation, the translator will return the keyword, unless there is a translation for <code>eng</code>. (In that case, English "translation" will be used as default translation) The following is formatting example for txt file. <pre> // If the first two characters are '//', this line will be ignored. Nightcat Horn Colour|kor$¹ã°í¾çÀÌ »Ô »ö±ò // If you have variables, avoid using partial sentences. Not every language has the same subject-verb-object order. Press &lt;ThrowKey&gt; to stab.|kor$&lt;ThrowKey&gt; ¹öưÀ» ´­·¯ Â±â. // When translating the shorter-phrase, the translation might be sensitive with context, but English one does not. Duplicate key causes error(You can check exceptionLog.txt for duplicates), so you can set 'eng' translation for these cases. Property_as of possession|eng$Property|kor$¼ÒÀ¯¹° Property_as of quality|eng$Property|kor$¼Ó¼º // For line-breaks, use \n. (In code, it¡¯d be \\n) Each line represents a phrase, so you can¡¯t use actual line-break in a single chunk. LINE\nBREAK|kor$ÁÙ\n¹Ù²Þ</pre> ==== Running Translation ==== And here are some examples in code. Yes, running every text through the <code>Translate</code> method is tedious, but this is usually how it's done in Rain World or many other games. Make sure to check your mod in another language to confirm you haven’t missed any item. <syntaxhighlight lang="c#"> labelCpkrRadio.text = MyPlugin.Translate("Nightcat Horn Colour"); instance.room.game.cameras[0].hud.textPrompt.AddMessage(MyPlugin.Translate("Press <ThrowKey> to stab.").Replace("<ThrowKey>", k.ToString())); // k is variable in this example. labelLineBreak.text = MyPlugin.Translate("LINE\\nBREAK"); </syntaxhighlight> <!-- These aren't the part of tutorial but more of tips. This does not just apply for making Rain World mods but to general, whenever you're making something that supports translation. * When you have variables in your sentence, do not use partial phrases and Frankenstein it later with <code>string.Concat</code>. Not every language has the same grammar order of subject-verb-object as English. * Leave credits to the translators, since you¡¯re most likely getting volunteers from them. This is both good for showing gratitude to the translators and keeping the quality of the translation. The lack of credits equals a lack of responsibility. * Do not use machine translation. That usually hurts the user experience rather than enhancing it. --> == Acceptable Types == As of Config Machine <code>v1.5.1</code>, it accepts the following types and uses provided UIconfig. (Height is the pixel height that how much this ConfigEntry would use. And each entry get 20 pixeled gaps in between) {|class="wikitable" !align="right" width="23%"| type !align="center" width="29%"| UIconfig !align="right" width="23%"| Height !width="23%"| Note |- |align="right"| bool |align="center"| OpCheckBox |align="right"| 60 | |- |align="right"| byte |align="center"| OpSliderSubtle |align="right"| 90 | Range: [0, 20] |- |align="right"| uint |align="center"| OpSlider |align="right"| 90 | Range: [0, 100] |- |align="right"| int |align="center"| OpTextBox |align="right"| 60 | Accepts: Int |- |align="right"| float |align="center"| OpTextBox |align="right"| 60 | Accepts: Float |- |align="right"| string(Hex) |align="center"| OpColorPicker |align="right"| 170 | When defaultValue is Hex |- |align="right"| string |align="center"| OpTextBox |align="right"| 60 | When defaultValue is not Hex; Accepts: ASCII |- |align="right"| KeyCode |align="center"| OpKeyBinder |align="right"| 100 | |- |align="right"| enumType |align="center"| OpResourceSelector |align="right"| 60 | |- |align="right"| default |align="center"| N/A |align="right"| | Will warn the user that this plugin has ConfigEntry that’s not supported by Config Machine |} [[Category:Dependencies]] [[Category:Code Mods]] 17db83ebda82705ae3221fb0086dc7ba12ca8916 184 178 2022-08-10T20:16:09Z Thalber 3 wikitext text/x-wiki {{Cleanup}} '''Configmachine''' is a dependency mod that allows other mods to easily create in-game config GUI. It's currently shipped with [[BepInEx]] installation. == Features == === OptionInterface === This is the most common method of adding config screen to your mod. ==== Registering ==== '''OptionalUI.OptionInterface''' is the base class for option interfaces. <syntaxhighlight lang="csharp"> public class MyOI : OptionInterface { public MyOI() : base (plugin: MyPlugin.instance) // Your BaseUnityPlugin instance. Examples assume you have a static singleton instance of your mod. { } } </syntaxhighlight> Now add <code>LoadOI</code> static method in your <code>BaseUnityPlugin</code> class that returns your OptionInterface. <syntaxhighlight lang="c#"> public static OptionInterface LoadOI() => return new MyOI(); //set return type to "object" if you want your mod to be loaded even if CM is not. In that case, you will need to handle CM's absence on your own. </syntaxhighlight> ==== Designing GUI ==== For designing your GUI, using [https://inkscape.org/ Inkscape] is strongly suggested. With Inkscape, create a file with 600 x 600 pixel resolution, then enable [View] - [Canvas Orientation] - [Flip Vertically]. (Alternatively, you can use any CAD program which has up and right as positive axis by default) <!--The image below is a diagram of <code>Colorfoot</code>’s first <code>OpTab</code>.--> [[File:Colorfoot-GUI.png|thumb|right|alt=Colorfoot's GUI as an example|Colorfoot's GUI as an example]] All UIelements have bottom-left <code>pos</code>ition and rectangular <code>size</code>. (Some have <code>fixedSize</code> which you can see from the summary of their constructors). Think every element like rectangles, and arrange them as you need. (Circular UIelements have <code>rad</code> instead; You can consider them as a square with 2 * rad for its dimensions) [[File:Colorfoot-GUI0.png|thumb|none|alt=Example GUI Positioning|Example GUI Positioning]] For <code>pos</code> parameters, use the relative coordinate from bottom-left from the canvas to your item. For <code>size</code> parameters, use their size in pixel. If you’re using Inkscape with [Flip Vertically] setting on, you can get those from their properties without any calculation. [[File:Colorfoot-Inkscape.png|thumb|none|alt=Example GUI Inkscape|Example GUI in Inkscape]] Here are some tips for designing GUI: * If you have many things to display, organise them with categories and use <code>OpRect</code> to surround them. * You don’t have to put everything in a single <code>OpTab</code>. If the canvas gets crowded, disperse your items for easier readability. * Try to avoid using smaller <code>OpScrollBox</code>s to store many things in one place even if that’s an option: The users cannot see everything in a single screen which reduces usability greatly. ==== Initialization ==== <code>OptionInterface.Initialize</code> is called in IntroRoll(for loading configuration) and ConfigMenu (for displaying to users). You can check whether Initialize is called in ConfigMenu or not with <code>OptionInterface.isOptionMenu</code>. It usually goes like this following example: <syntaxhighlight lang="csharp"> public override void Initialize() { base.Initialize(); // This should be called before everything else Tabs = new OpTab[2]; // you can have up to 20 tabs Tabs[0] = new OpTab("Main"); // Each OpTab is 600 x 600 pixel sized canvas Tabs[1] = new OpTab("Second") { color = Color.cyan }; // You can change its button and canvas colour too // After Initializing Tabs, create UIelements and add them to tabs } </syntaxhighlight> Now initialize <code>UIelement</code>s and add them to <code>OpTab</code> (or <code>OpScrollBox</code>). The Z-order (the order in which they’re drawn) of <code>UIelement</code>s is the order of constructors, ''not'' the order they’re added to <code>OpTab</code>. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpLabel(100f, 500f, "My Text") { description = "This is My Text" }); // Any UIelement can have description, which will be shown // at the bottom of the screen when the mouse cursor is over it </syntaxhighlight> <code>UIconfig</code>s are a subcategory of <code>UIelement</code> which have <code>key</code> and <code>value</code> for storing user input values, both of them get saved automatically by Config Machine. Their constructor accepts <code>key</code> and <code>defaultValue</code> on top of everything else. <code>key</code> must be unique for all elements in your OI unless they are cosmetic. Setting the key to empty or anything that starts with <code>_</code> (underbar) will turn it <code>cosmetic</code>, and the value won’t be saved. Cosmetic UIconfig is useful when you want to have provided <code>UIconfig</code> for UI purpose but not for an actual configurable. (Similarly, ModID that starts with <code>_</code> will be completely ignored by Config Machine) <syntaxhighlight lang="csharp"> OpCheckBox chkExample = new OpCheckBox(260f, 360f, "Example", true); Tabs[0].AddItems(chkExample, new OpLabel(260f, 390f, "Enable Example") { bumpBehav = chkExample.bumpBehav }); // BumpBehaviour is Config Machine's custom class that allows smoothly animated reaction with the input // Setting OpLabel's bumpBehav to other UIconfig/UItrigger's bumpBehav allows it to highlight with that element </syntaxhighlight> <code>UItrigger</code>s are the other subcategory of <code>UIelement</code>s which have <code>signal</code>s. When the user activates an <code>UItrigger</code> in some way, it will call the <code>Signal</code> function in OptionInterface which will be explained later. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpSimpleButton(new Vector2(400f, 200f), new Vector2(100f, 24f), "press", "Press Me")); </syntaxhighlight> ==== Update ==== <code>Update</code> function is called every frame when the game is in ConfigMenu, and this OptionInterface is currently active (The user has currently selected this mod from the list on left). This is useful to make reactive GUI, especially since each <code>UIconfig</code> instance can have only one value saved. The following example code uses cosmetic <code>OpRadioButtonGroup</code> to have four <code>OpColorPicker</code>s in a single spot. <syntaxhighlight lang="csharp"> private OpRadioButtonGroup rbgSelect; private int select; private OpColorPicker[] cpkPlayers; public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; select = 0; rbgSelect = new OpRadioButtonGroup("_", select); Tabs[0].AddItems(rbgSelect); rbgSelect.SetButtons(new OpRadioButton[] { new OpRadioButton(50f, 100f){ description = "The Survivor"}, new OpRadioButton(100f, 100f){ description = "The Monk"}, new OpRadioButton(150f, 100f){ description = "The Hunter"}, new OpRadioButton(200f, 100f){ description = "The Nightcat"} } ); OpColorPicker[] cpkPlayers = new OpColorPicker[4]; for (int i = 0; i < 4; i++) { Tabs[0].AddItems(new OpLabel(50f * i, 70f, rbgSelect.buttons[i].description) { bumpBehav = rbgSelect.buttons[i].bumpBehav }); cpkPlayers[i] = new OpColorPicker(new Vector2(100f, 300f), $"Color{i}", "FFFFFF"); cpkPlayers[i].Hide(); } cpkPlayers[select].Show(); Tabs[0].AddItems(cpkPlayers); } public override void Update(float dt) { base.Update(dt); // dt is deltaTime if (select != rbgSelect.valueInt) { for (int i = 0; i < cpkPlayers.Length; i++) { cpkPlayers[i].Hide(); } select = rbgSelect.valueInt; cpkPlayers[select].Show(); } } </syntaxhighlight> ==== ConfigOnChange ==== <code>ConfigOnChange</code> is called whenever <code>config</code> Dictionary is updated, mainly when Config Machine loads OptionInterfaces in IntroRoll, and when the user saves changes of configuration in ConfigMenu. Override this method to grab your configurable values. <code>config</code> Dictionary is where <code>UIconfig</code>’s value is stored. The following is an example of how to convert a string value to the corresponding type. <syntaxhighlight lang="csharp">public override void ConfigOnChange() { base.ConfigOnChange(); MyMod.config.myInt = int.Parse(config["keyInt"]); MyMod.config.myFloat = float.Parse(config["keyFloat"]); MyMod.config.myKey = OpKeyBinder.StringToKeyCode(config["keyKey"]); MyMod.config.myColor = OpColorPicker.HexToColor(config["keyColor"]); } </syntaxhighlight> ==== Signal ==== <code>Signal</code> is called when the user has interacted with <code>UItrigger</code>. Override this to have your OI to react. <syntaxhighlight lang="csharp"> public override void Signal(UItrigger trigger, string signal) { switch (signal) { case "reset": ConfigMenu.ResetCurrentConfig(); // This is the same as pressing Reset Config Button. break; } } </syntaxhighlight> === Generated OIs === <code>GeneratedOI</code> is a child class of <code>OptionInterface</code> that helps generating fixed-format GUI with less effort. <span id="displaying-basic-profile"></span> ==== Displaying Basic Profile ==== Simply inheriting <code>GeneratedOI</code> instead of <code>OptionInterface</code> works. This does make your mod dependent to Config Machine, and Config Machine generates GUI to display the basic information of your mod without this dependency. So this is only useful when you’re using OptionInterface for other features, like its Translation API. <syntaxhighlight lang="c#"> public class MyOI : GeneratedOI { private const string desc = "Changes this thing and that thing"; public MyOI() : base(plugin: MyPlugin.instance, desc) { transFile = "MyPlugin.Translation.txt"; } } </syntaxhighlight> The code above would generate a GUI like the following image: [[File:GeneratedOI-sample.png|thumb|none|alt=GeneratedOI Sample|GeneratedOI Sample]] You can also use its static method <code>AddBasicProfile</code> for basic profiles on top of the canvas. This also has an overload that accepts <code>OpScrollBox</code> instead of <code>OpTab</code>, if you have <code>OpScrollBox</code> replacing <code>OpTab</code>. <syntaxhighlight lang="c#"> public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; GeneratedOI.AddBasicProfile(Tabs[0], rwMod); Tabs[0].AddItems(new OpCheckBox(100f, 350f, "EnableStuff", false) { description = "Enables this stuff" }); } </syntaxhighlight> ==== BepInEx.Configuration ==== If you don't provide an OptionInterface, BepInEx can generate a simple config screen from your [[BepInPlugins|plugin]]'s config bindings (see <code>BepInEx.Configuration</code>). If this happens, CM will not create a separate file to store your config values. This method has upsides and downsides. * You don’t need to reference Config Machine in your project, and this doesn’t create a dependency for Config Machine. * The users can configure the plugin by opening the cfg file in Notepad outside the game. * However, you do not have control on detailed GUI design. First, we need <code>ConfigEntry</code> which you can bind to the <code>Config</code> property of <code>BaseUnityPlugin</code>. Consult [https://docs.bepinex.dev/articles/dev_guide/plugin_tutorial/4_configuration.html BepInEx Documentation] for farther detail. <syntaxhighlight lang="c#"> public static ConfigEntry<string> cfgText; public static ConfigEntry<bool> cfgCheck; void Awake() { cfgText = Config.Bind( "General", // section: defines which OpTab this will go "My Setting", // key: the name of setting "Hello, world!" // defaultValue "This is a description. It does things." // The description will be shown the right side of UIconfig // When you hover your mouse on UIconfig, // the first sentence will be displayed at the bottom of the screen ); cfgCheck = Config.Bind("General", "My Other Setting", true, "Another description is this."); } </syntaxhighlight> To access those settings, use <code>Value</code>. <syntaxhighlight lang="c#"> if (cfgCheck.Value) { Logger.LogMessage(cfgText.Value); } </syntaxhighlight> === Translation Support === While you can support translation for your mod on your own, Config Machine also offers translation solution. ==== Preparation ==== <code>OptionInterface</code> has a method called <code>Translate</code>, and when it's initially called, it will load specified (<code>transFile</code>) txt file from your assembly and make Dictionary depending on Rain World's language setting. In <code>BaseUnityPlugin.LoadOI</code> method, store the <code>OptionInterface</code> instance in somewhere before returning it. <syntaxhighlight lang="c#"> public static MyOI oi; public static MyOI LoadOI() { oi = new MyOI(); return oi; } </syntaxhighlight> Then make a static method that calls the translation method. <syntaxhighlight lang="c#">public static string Translate(string orig) { if (oi != null) { return oi.Translate(orig); } return orig; } </syntaxhighlight> Now when you need to translate something, you can pass your string through this method. ==== Writing Translation txt ==== Create a txt file that contains translation, too. Add txt file to your project, ''make sure'' that its encoding is <code>UTF-8</code>, then set it to be [Embedded Resources] for its compile setting. Then, in the constructor of your OptionInterface, set <code>transFile</code> to that resource name. If you have not put it in any folder, it's usually <code>&lt;ProjectName&gt;.&lt;TxtFileName&gt;.txt</code>, but you might get it wrong. If it's wrong when <code>OptionInterface.Translate</code> is initially called, Config Machine will log all the resources in your assembly in exceptionLog.txt so you can copy from it. <syntaxhighlight lang="c#">public MyOI() : base(plugin: MyPlugin.instance) { this.transFile = "MyPlugin.Translation.txt"; // if you do not know the resource name, just call Translate. // ConfigMachine will log all the resources in your assembly in exceptionLog.txt. } </syntaxhighlight> The format of the translation txt file for Config Machine is quite primitive. First, you add a keyword, then <code>|</code> for language separator, then language ID (<code>eng, ita, ger, spa, por, kor, jap, rus)</code>), <code>$</code> for another separator, then translation. If there is no translation, the translator will return the keyword, unless there is a translation for <code>eng</code>. (In that case, English "translation" will be used as default translation) The following is formatting example for txt file. <pre> // If the first two characters are '//', this line will be ignored. Nightcat Horn Colour|kor$¹ã°í¾çÀÌ »Ô »ö±ò // If you have variables, avoid using partial sentences. Not every language has the same subject-verb-object order. Press &lt;ThrowKey&gt; to stab.|kor$&lt;ThrowKey&gt; ¹öưÀ» ´­·¯ Â±â. // When translating the shorter-phrase, the translation might be sensitive with context, but English one does not. Duplicate key causes error(You can check exceptionLog.txt for duplicates), so you can set 'eng' translation for these cases. Property_as of possession|eng$Property|kor$¼ÒÀ¯¹° Property_as of quality|eng$Property|kor$¼Ó¼º // For line-breaks, use \n. (In code, it¡¯d be \\n) Each line represents a phrase, so you can¡¯t use actual line-break in a single chunk. LINE\nBREAK|kor$ÁÙ\n¹Ù²Þ</pre> ==== Running Translation ==== And here are some examples in code. Yes, running every text through the <code>Translate</code> method is tedious, but this is usually how it's done in Rain World or many other games. Make sure to check your mod in another language to confirm you haven’t missed any item. <syntaxhighlight lang="c#"> labelCpkrRadio.text = MyPlugin.Translate("Nightcat Horn Colour"); instance.room.game.cameras[0].hud.textPrompt.AddMessage(MyPlugin.Translate("Press <ThrowKey> to stab.").Replace("<ThrowKey>", k.ToString())); // k is variable in this example. labelLineBreak.text = MyPlugin.Translate("LINE\\nBREAK"); </syntaxhighlight> <!-- These aren't the part of tutorial but more of tips. This does not just apply for making Rain World mods but to general, whenever you're making something that supports translation. * When you have variables in your sentence, do not use partial phrases and Frankenstein it later with <code>string.Concat</code>. Not every language has the same grammar order of subject-verb-object as English. * Leave credits to the translators, since you¡¯re most likely getting volunteers from them. This is both good for showing gratitude to the translators and keeping the quality of the translation. The lack of credits equals a lack of responsibility. * Do not use machine translation. That usually hurts the user experience rather than enhancing it. --> == Acceptable Types == As of Config Machine <code>v1.5.1</code>, it accepts the following types and uses provided UIconfig. (Height is the pixel height that how much this ConfigEntry would use. And each entry get 20 pixeled gaps in between) {|class="wikitable" !align="right" width="23%"| type !align="center" width="29%"| UIconfig !align="right" width="23%"| Height !width="23%"| Note |- |align="right"| bool |align="center"| OpCheckBox |align="right"| 60 | |- |align="right"| byte |align="center"| OpSliderSubtle |align="right"| 90 | Range: [0, 20] |- |align="right"| uint |align="center"| OpSlider |align="right"| 90 | Range: [0, 100] |- |align="right"| int |align="center"| OpTextBox |align="right"| 60 | Accepts: Int |- |align="right"| float |align="center"| OpTextBox |align="right"| 60 | Accepts: Float |- |align="right"| string(Hex) |align="center"| OpColorPicker |align="right"| 170 | When defaultValue is Hex |- |align="right"| string |align="center"| OpTextBox |align="right"| 60 | When defaultValue is not Hex; Accepts: ASCII |- |align="right"| KeyCode |align="center"| OpKeyBinder |align="right"| 100 | |- |align="right"| enumType |align="center"| OpResourceSelector |align="right"| 60 | |- |align="right"| default |align="center"| N/A |align="right"| | Will warn the user that this plugin has ConfigEntry that’s not supported by Config Machine |} == Available UI Elements == Full list of available UI elements can be found [[ConfigMachine/Provided UI|here]] [[Category:Dependencies]] [[Category:Code Mods]] 4e3919cb1c2ba3d547843347d693b11e493c7d1f 185 184 2022-08-10T20:16:23Z Thalber 3 /* Available UI Elements */ wikitext text/x-wiki {{Cleanup}} '''Configmachine''' is a dependency mod that allows other mods to easily create in-game config GUI. It's currently shipped with [[BepInEx]] installation. == Features == === OptionInterface === This is the most common method of adding config screen to your mod. ==== Registering ==== '''OptionalUI.OptionInterface''' is the base class for option interfaces. <syntaxhighlight lang="csharp"> public class MyOI : OptionInterface { public MyOI() : base (plugin: MyPlugin.instance) // Your BaseUnityPlugin instance. Examples assume you have a static singleton instance of your mod. { } } </syntaxhighlight> Now add <code>LoadOI</code> static method in your <code>BaseUnityPlugin</code> class that returns your OptionInterface. <syntaxhighlight lang="c#"> public static OptionInterface LoadOI() => return new MyOI(); //set return type to "object" if you want your mod to be loaded even if CM is not. In that case, you will need to handle CM's absence on your own. </syntaxhighlight> ==== Designing GUI ==== For designing your GUI, using [https://inkscape.org/ Inkscape] is strongly suggested. With Inkscape, create a file with 600 x 600 pixel resolution, then enable [View] - [Canvas Orientation] - [Flip Vertically]. (Alternatively, you can use any CAD program which has up and right as positive axis by default) <!--The image below is a diagram of <code>Colorfoot</code>’s first <code>OpTab</code>.--> [[File:Colorfoot-GUI.png|thumb|right|alt=Colorfoot's GUI as an example|Colorfoot's GUI as an example]] All UIelements have bottom-left <code>pos</code>ition and rectangular <code>size</code>. (Some have <code>fixedSize</code> which you can see from the summary of their constructors). Think every element like rectangles, and arrange them as you need. (Circular UIelements have <code>rad</code> instead; You can consider them as a square with 2 * rad for its dimensions) [[File:Colorfoot-GUI0.png|thumb|none|alt=Example GUI Positioning|Example GUI Positioning]] For <code>pos</code> parameters, use the relative coordinate from bottom-left from the canvas to your item. For <code>size</code> parameters, use their size in pixel. If you’re using Inkscape with [Flip Vertically] setting on, you can get those from their properties without any calculation. [[File:Colorfoot-Inkscape.png|thumb|none|alt=Example GUI Inkscape|Example GUI in Inkscape]] Here are some tips for designing GUI: * If you have many things to display, organise them with categories and use <code>OpRect</code> to surround them. * You don’t have to put everything in a single <code>OpTab</code>. If the canvas gets crowded, disperse your items for easier readability. * Try to avoid using smaller <code>OpScrollBox</code>s to store many things in one place even if that’s an option: The users cannot see everything in a single screen which reduces usability greatly. ==== Initialization ==== <code>OptionInterface.Initialize</code> is called in IntroRoll(for loading configuration) and ConfigMenu (for displaying to users). You can check whether Initialize is called in ConfigMenu or not with <code>OptionInterface.isOptionMenu</code>. It usually goes like this following example: <syntaxhighlight lang="csharp"> public override void Initialize() { base.Initialize(); // This should be called before everything else Tabs = new OpTab[2]; // you can have up to 20 tabs Tabs[0] = new OpTab("Main"); // Each OpTab is 600 x 600 pixel sized canvas Tabs[1] = new OpTab("Second") { color = Color.cyan }; // You can change its button and canvas colour too // After Initializing Tabs, create UIelements and add them to tabs } </syntaxhighlight> Now initialize <code>UIelement</code>s and add them to <code>OpTab</code> (or <code>OpScrollBox</code>). The Z-order (the order in which they’re drawn) of <code>UIelement</code>s is the order of constructors, ''not'' the order they’re added to <code>OpTab</code>. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpLabel(100f, 500f, "My Text") { description = "This is My Text" }); // Any UIelement can have description, which will be shown // at the bottom of the screen when the mouse cursor is over it </syntaxhighlight> <code>UIconfig</code>s are a subcategory of <code>UIelement</code> which have <code>key</code> and <code>value</code> for storing user input values, both of them get saved automatically by Config Machine. Their constructor accepts <code>key</code> and <code>defaultValue</code> on top of everything else. <code>key</code> must be unique for all elements in your OI unless they are cosmetic. Setting the key to empty or anything that starts with <code>_</code> (underbar) will turn it <code>cosmetic</code>, and the value won’t be saved. Cosmetic UIconfig is useful when you want to have provided <code>UIconfig</code> for UI purpose but not for an actual configurable. (Similarly, ModID that starts with <code>_</code> will be completely ignored by Config Machine) <syntaxhighlight lang="csharp"> OpCheckBox chkExample = new OpCheckBox(260f, 360f, "Example", true); Tabs[0].AddItems(chkExample, new OpLabel(260f, 390f, "Enable Example") { bumpBehav = chkExample.bumpBehav }); // BumpBehaviour is Config Machine's custom class that allows smoothly animated reaction with the input // Setting OpLabel's bumpBehav to other UIconfig/UItrigger's bumpBehav allows it to highlight with that element </syntaxhighlight> <code>UItrigger</code>s are the other subcategory of <code>UIelement</code>s which have <code>signal</code>s. When the user activates an <code>UItrigger</code> in some way, it will call the <code>Signal</code> function in OptionInterface which will be explained later. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpSimpleButton(new Vector2(400f, 200f), new Vector2(100f, 24f), "press", "Press Me")); </syntaxhighlight> ==== Update ==== <code>Update</code> function is called every frame when the game is in ConfigMenu, and this OptionInterface is currently active (The user has currently selected this mod from the list on left). This is useful to make reactive GUI, especially since each <code>UIconfig</code> instance can have only one value saved. The following example code uses cosmetic <code>OpRadioButtonGroup</code> to have four <code>OpColorPicker</code>s in a single spot. <syntaxhighlight lang="csharp"> private OpRadioButtonGroup rbgSelect; private int select; private OpColorPicker[] cpkPlayers; public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; select = 0; rbgSelect = new OpRadioButtonGroup("_", select); Tabs[0].AddItems(rbgSelect); rbgSelect.SetButtons(new OpRadioButton[] { new OpRadioButton(50f, 100f){ description = "The Survivor"}, new OpRadioButton(100f, 100f){ description = "The Monk"}, new OpRadioButton(150f, 100f){ description = "The Hunter"}, new OpRadioButton(200f, 100f){ description = "The Nightcat"} } ); OpColorPicker[] cpkPlayers = new OpColorPicker[4]; for (int i = 0; i < 4; i++) { Tabs[0].AddItems(new OpLabel(50f * i, 70f, rbgSelect.buttons[i].description) { bumpBehav = rbgSelect.buttons[i].bumpBehav }); cpkPlayers[i] = new OpColorPicker(new Vector2(100f, 300f), $"Color{i}", "FFFFFF"); cpkPlayers[i].Hide(); } cpkPlayers[select].Show(); Tabs[0].AddItems(cpkPlayers); } public override void Update(float dt) { base.Update(dt); // dt is deltaTime if (select != rbgSelect.valueInt) { for (int i = 0; i < cpkPlayers.Length; i++) { cpkPlayers[i].Hide(); } select = rbgSelect.valueInt; cpkPlayers[select].Show(); } } </syntaxhighlight> ==== ConfigOnChange ==== <code>ConfigOnChange</code> is called whenever <code>config</code> Dictionary is updated, mainly when Config Machine loads OptionInterfaces in IntroRoll, and when the user saves changes of configuration in ConfigMenu. Override this method to grab your configurable values. <code>config</code> Dictionary is where <code>UIconfig</code>’s value is stored. The following is an example of how to convert a string value to the corresponding type. <syntaxhighlight lang="csharp">public override void ConfigOnChange() { base.ConfigOnChange(); MyMod.config.myInt = int.Parse(config["keyInt"]); MyMod.config.myFloat = float.Parse(config["keyFloat"]); MyMod.config.myKey = OpKeyBinder.StringToKeyCode(config["keyKey"]); MyMod.config.myColor = OpColorPicker.HexToColor(config["keyColor"]); } </syntaxhighlight> ==== Signal ==== <code>Signal</code> is called when the user has interacted with <code>UItrigger</code>. Override this to have your OI to react. <syntaxhighlight lang="csharp"> public override void Signal(UItrigger trigger, string signal) { switch (signal) { case "reset": ConfigMenu.ResetCurrentConfig(); // This is the same as pressing Reset Config Button. break; } } </syntaxhighlight> === Generated OIs === <code>GeneratedOI</code> is a child class of <code>OptionInterface</code> that helps generating fixed-format GUI with less effort. <span id="displaying-basic-profile"></span> ==== Displaying Basic Profile ==== Simply inheriting <code>GeneratedOI</code> instead of <code>OptionInterface</code> works. This does make your mod dependent to Config Machine, and Config Machine generates GUI to display the basic information of your mod without this dependency. So this is only useful when you’re using OptionInterface for other features, like its Translation API. <syntaxhighlight lang="c#"> public class MyOI : GeneratedOI { private const string desc = "Changes this thing and that thing"; public MyOI() : base(plugin: MyPlugin.instance, desc) { transFile = "MyPlugin.Translation.txt"; } } </syntaxhighlight> The code above would generate a GUI like the following image: [[File:GeneratedOI-sample.png|thumb|none|alt=GeneratedOI Sample|GeneratedOI Sample]] You can also use its static method <code>AddBasicProfile</code> for basic profiles on top of the canvas. This also has an overload that accepts <code>OpScrollBox</code> instead of <code>OpTab</code>, if you have <code>OpScrollBox</code> replacing <code>OpTab</code>. <syntaxhighlight lang="c#"> public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; GeneratedOI.AddBasicProfile(Tabs[0], rwMod); Tabs[0].AddItems(new OpCheckBox(100f, 350f, "EnableStuff", false) { description = "Enables this stuff" }); } </syntaxhighlight> ==== BepInEx.Configuration ==== If you don't provide an OptionInterface, BepInEx can generate a simple config screen from your [[BepInPlugins|plugin]]'s config bindings (see <code>BepInEx.Configuration</code>). If this happens, CM will not create a separate file to store your config values. This method has upsides and downsides. * You don’t need to reference Config Machine in your project, and this doesn’t create a dependency for Config Machine. * The users can configure the plugin by opening the cfg file in Notepad outside the game. * However, you do not have control on detailed GUI design. First, we need <code>ConfigEntry</code> which you can bind to the <code>Config</code> property of <code>BaseUnityPlugin</code>. Consult [https://docs.bepinex.dev/articles/dev_guide/plugin_tutorial/4_configuration.html BepInEx Documentation] for farther detail. <syntaxhighlight lang="c#"> public static ConfigEntry<string> cfgText; public static ConfigEntry<bool> cfgCheck; void Awake() { cfgText = Config.Bind( "General", // section: defines which OpTab this will go "My Setting", // key: the name of setting "Hello, world!" // defaultValue "This is a description. It does things." // The description will be shown the right side of UIconfig // When you hover your mouse on UIconfig, // the first sentence will be displayed at the bottom of the screen ); cfgCheck = Config.Bind("General", "My Other Setting", true, "Another description is this."); } </syntaxhighlight> To access those settings, use <code>Value</code>. <syntaxhighlight lang="c#"> if (cfgCheck.Value) { Logger.LogMessage(cfgText.Value); } </syntaxhighlight> === Translation Support === While you can support translation for your mod on your own, Config Machine also offers translation solution. ==== Preparation ==== <code>OptionInterface</code> has a method called <code>Translate</code>, and when it's initially called, it will load specified (<code>transFile</code>) txt file from your assembly and make Dictionary depending on Rain World's language setting. In <code>BaseUnityPlugin.LoadOI</code> method, store the <code>OptionInterface</code> instance in somewhere before returning it. <syntaxhighlight lang="c#"> public static MyOI oi; public static MyOI LoadOI() { oi = new MyOI(); return oi; } </syntaxhighlight> Then make a static method that calls the translation method. <syntaxhighlight lang="c#">public static string Translate(string orig) { if (oi != null) { return oi.Translate(orig); } return orig; } </syntaxhighlight> Now when you need to translate something, you can pass your string through this method. ==== Writing Translation txt ==== Create a txt file that contains translation, too. Add txt file to your project, ''make sure'' that its encoding is <code>UTF-8</code>, then set it to be [Embedded Resources] for its compile setting. Then, in the constructor of your OptionInterface, set <code>transFile</code> to that resource name. If you have not put it in any folder, it's usually <code>&lt;ProjectName&gt;.&lt;TxtFileName&gt;.txt</code>, but you might get it wrong. If it's wrong when <code>OptionInterface.Translate</code> is initially called, Config Machine will log all the resources in your assembly in exceptionLog.txt so you can copy from it. <syntaxhighlight lang="c#">public MyOI() : base(plugin: MyPlugin.instance) { this.transFile = "MyPlugin.Translation.txt"; // if you do not know the resource name, just call Translate. // ConfigMachine will log all the resources in your assembly in exceptionLog.txt. } </syntaxhighlight> The format of the translation txt file for Config Machine is quite primitive. First, you add a keyword, then <code>|</code> for language separator, then language ID (<code>eng, ita, ger, spa, por, kor, jap, rus)</code>), <code>$</code> for another separator, then translation. If there is no translation, the translator will return the keyword, unless there is a translation for <code>eng</code>. (In that case, English "translation" will be used as default translation) The following is formatting example for txt file. <pre> // If the first two characters are '//', this line will be ignored. Nightcat Horn Colour|kor$¹ã°í¾çÀÌ »Ô »ö±ò // If you have variables, avoid using partial sentences. Not every language has the same subject-verb-object order. Press &lt;ThrowKey&gt; to stab.|kor$&lt;ThrowKey&gt; ¹öưÀ» ´­·¯ Â±â. // When translating the shorter-phrase, the translation might be sensitive with context, but English one does not. Duplicate key causes error(You can check exceptionLog.txt for duplicates), so you can set 'eng' translation for these cases. Property_as of possession|eng$Property|kor$¼ÒÀ¯¹° Property_as of quality|eng$Property|kor$¼Ó¼º // For line-breaks, use \n. (In code, it¡¯d be \\n) Each line represents a phrase, so you can¡¯t use actual line-break in a single chunk. LINE\nBREAK|kor$ÁÙ\n¹Ù²Þ</pre> ==== Running Translation ==== And here are some examples in code. Yes, running every text through the <code>Translate</code> method is tedious, but this is usually how it's done in Rain World or many other games. Make sure to check your mod in another language to confirm you haven’t missed any item. <syntaxhighlight lang="c#"> labelCpkrRadio.text = MyPlugin.Translate("Nightcat Horn Colour"); instance.room.game.cameras[0].hud.textPrompt.AddMessage(MyPlugin.Translate("Press <ThrowKey> to stab.").Replace("<ThrowKey>", k.ToString())); // k is variable in this example. labelLineBreak.text = MyPlugin.Translate("LINE\\nBREAK"); </syntaxhighlight> <!-- These aren't the part of tutorial but more of tips. This does not just apply for making Rain World mods but to general, whenever you're making something that supports translation. * When you have variables in your sentence, do not use partial phrases and Frankenstein it later with <code>string.Concat</code>. Not every language has the same grammar order of subject-verb-object as English. * Leave credits to the translators, since you¡¯re most likely getting volunteers from them. This is both good for showing gratitude to the translators and keeping the quality of the translation. The lack of credits equals a lack of responsibility. * Do not use machine translation. That usually hurts the user experience rather than enhancing it. --> == Acceptable Types == As of Config Machine <code>v1.5.1</code>, it accepts the following types and uses provided UIconfig. (Height is the pixel height that how much this ConfigEntry would use. And each entry get 20 pixeled gaps in between) {|class="wikitable" !align="right" width="23%"| type !align="center" width="29%"| UIconfig !align="right" width="23%"| Height !width="23%"| Note |- |align="right"| bool |align="center"| OpCheckBox |align="right"| 60 | |- |align="right"| byte |align="center"| OpSliderSubtle |align="right"| 90 | Range: [0, 20] |- |align="right"| uint |align="center"| OpSlider |align="right"| 90 | Range: [0, 100] |- |align="right"| int |align="center"| OpTextBox |align="right"| 60 | Accepts: Int |- |align="right"| float |align="center"| OpTextBox |align="right"| 60 | Accepts: Float |- |align="right"| string(Hex) |align="center"| OpColorPicker |align="right"| 170 | When defaultValue is Hex |- |align="right"| string |align="center"| OpTextBox |align="right"| 60 | When defaultValue is not Hex; Accepts: ASCII |- |align="right"| KeyCode |align="center"| OpKeyBinder |align="right"| 100 | |- |align="right"| enumType |align="center"| OpResourceSelector |align="right"| 60 | |- |align="right"| default |align="center"| N/A |align="right"| | Will warn the user that this plugin has ConfigEntry that’s not supported by Config Machine |} == Available UI Elements == Full list of available UI elements can be found [[ConfigMachine/Provided UI|here]]. [[Category:Dependencies]] [[Category:Code Mods]] 594097bcded1586164072bb594339e22f1347faa 186 185 2022-08-10T20:16:48Z Thalber 3 /* Available UI Elements */ wikitext text/x-wiki {{Cleanup}} '''Configmachine''' is a dependency mod that allows other mods to easily create in-game config GUI. It's currently shipped with [[BepInEx]] installation. == Features == === OptionInterface === This is the most common method of adding config screen to your mod. ==== Registering ==== '''OptionalUI.OptionInterface''' is the base class for option interfaces. <syntaxhighlight lang="csharp"> public class MyOI : OptionInterface { public MyOI() : base (plugin: MyPlugin.instance) // Your BaseUnityPlugin instance. Examples assume you have a static singleton instance of your mod. { } } </syntaxhighlight> Now add <code>LoadOI</code> static method in your <code>BaseUnityPlugin</code> class that returns your OptionInterface. <syntaxhighlight lang="c#"> public static OptionInterface LoadOI() => return new MyOI(); //set return type to "object" if you want your mod to be loaded even if CM is not. In that case, you will need to handle CM's absence on your own. </syntaxhighlight> ==== Designing GUI ==== For designing your GUI, using [https://inkscape.org/ Inkscape] is strongly suggested. With Inkscape, create a file with 600 x 600 pixel resolution, then enable [View] - [Canvas Orientation] - [Flip Vertically]. (Alternatively, you can use any CAD program which has up and right as positive axis by default) <!--The image below is a diagram of <code>Colorfoot</code>’s first <code>OpTab</code>.--> [[File:Colorfoot-GUI.png|thumb|right|alt=Colorfoot's GUI as an example|Colorfoot's GUI as an example]] All UIelements have bottom-left <code>pos</code>ition and rectangular <code>size</code>. (Some have <code>fixedSize</code> which you can see from the summary of their constructors). Think every element like rectangles, and arrange them as you need. (Circular UIelements have <code>rad</code> instead; You can consider them as a square with 2 * rad for its dimensions) [[File:Colorfoot-GUI0.png|thumb|none|alt=Example GUI Positioning|Example GUI Positioning]] For <code>pos</code> parameters, use the relative coordinate from bottom-left from the canvas to your item. For <code>size</code> parameters, use their size in pixel. If you’re using Inkscape with [Flip Vertically] setting on, you can get those from their properties without any calculation. [[File:Colorfoot-Inkscape.png|thumb|none|alt=Example GUI Inkscape|Example GUI in Inkscape]] Here are some tips for designing GUI: * If you have many things to display, organise them with categories and use <code>OpRect</code> to surround them. * You don’t have to put everything in a single <code>OpTab</code>. If the canvas gets crowded, disperse your items for easier readability. * Try to avoid using smaller <code>OpScrollBox</code>s to store many things in one place even if that’s an option: The users cannot see everything in a single screen which reduces usability greatly. ==== Initialization ==== <code>OptionInterface.Initialize</code> is called in IntroRoll(for loading configuration) and ConfigMenu (for displaying to users). You can check whether Initialize is called in ConfigMenu or not with <code>OptionInterface.isOptionMenu</code>. It usually goes like this following example: <syntaxhighlight lang="csharp"> public override void Initialize() { base.Initialize(); // This should be called before everything else Tabs = new OpTab[2]; // you can have up to 20 tabs Tabs[0] = new OpTab("Main"); // Each OpTab is 600 x 600 pixel sized canvas Tabs[1] = new OpTab("Second") { color = Color.cyan }; // You can change its button and canvas colour too // After Initializing Tabs, create UIelements and add them to tabs } </syntaxhighlight> Now initialize <code>UIelement</code>s and add them to <code>OpTab</code> (or <code>OpScrollBox</code>). The Z-order (the order in which they’re drawn) of <code>UIelement</code>s is the order of constructors, ''not'' the order they’re added to <code>OpTab</code>. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpLabel(100f, 500f, "My Text") { description = "This is My Text" }); // Any UIelement can have description, which will be shown // at the bottom of the screen when the mouse cursor is over it </syntaxhighlight> <code>UIconfig</code>s are a subcategory of <code>UIelement</code> which have <code>key</code> and <code>value</code> for storing user input values, both of them get saved automatically by Config Machine. Their constructor accepts <code>key</code> and <code>defaultValue</code> on top of everything else. <code>key</code> must be unique for all elements in your OI unless they are cosmetic. Setting the key to empty or anything that starts with <code>_</code> (underbar) will turn it <code>cosmetic</code>, and the value won’t be saved. Cosmetic UIconfig is useful when you want to have provided <code>UIconfig</code> for UI purpose but not for an actual configurable. (Similarly, ModID that starts with <code>_</code> will be completely ignored by Config Machine) <syntaxhighlight lang="csharp"> OpCheckBox chkExample = new OpCheckBox(260f, 360f, "Example", true); Tabs[0].AddItems(chkExample, new OpLabel(260f, 390f, "Enable Example") { bumpBehav = chkExample.bumpBehav }); // BumpBehaviour is Config Machine's custom class that allows smoothly animated reaction with the input // Setting OpLabel's bumpBehav to other UIconfig/UItrigger's bumpBehav allows it to highlight with that element </syntaxhighlight> <code>UItrigger</code>s are the other subcategory of <code>UIelement</code>s which have <code>signal</code>s. When the user activates an <code>UItrigger</code> in some way, it will call the <code>Signal</code> function in OptionInterface which will be explained later. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpSimpleButton(new Vector2(400f, 200f), new Vector2(100f, 24f), "press", "Press Me")); </syntaxhighlight> ==== Update ==== <code>Update</code> function is called every frame when the game is in ConfigMenu, and this OptionInterface is currently active (The user has currently selected this mod from the list on left). This is useful to make reactive GUI, especially since each <code>UIconfig</code> instance can have only one value saved. The following example code uses cosmetic <code>OpRadioButtonGroup</code> to have four <code>OpColorPicker</code>s in a single spot. <syntaxhighlight lang="csharp"> private OpRadioButtonGroup rbgSelect; private int select; private OpColorPicker[] cpkPlayers; public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; select = 0; rbgSelect = new OpRadioButtonGroup("_", select); Tabs[0].AddItems(rbgSelect); rbgSelect.SetButtons(new OpRadioButton[] { new OpRadioButton(50f, 100f){ description = "The Survivor"}, new OpRadioButton(100f, 100f){ description = "The Monk"}, new OpRadioButton(150f, 100f){ description = "The Hunter"}, new OpRadioButton(200f, 100f){ description = "The Nightcat"} } ); OpColorPicker[] cpkPlayers = new OpColorPicker[4]; for (int i = 0; i < 4; i++) { Tabs[0].AddItems(new OpLabel(50f * i, 70f, rbgSelect.buttons[i].description) { bumpBehav = rbgSelect.buttons[i].bumpBehav }); cpkPlayers[i] = new OpColorPicker(new Vector2(100f, 300f), $"Color{i}", "FFFFFF"); cpkPlayers[i].Hide(); } cpkPlayers[select].Show(); Tabs[0].AddItems(cpkPlayers); } public override void Update(float dt) { base.Update(dt); // dt is deltaTime if (select != rbgSelect.valueInt) { for (int i = 0; i < cpkPlayers.Length; i++) { cpkPlayers[i].Hide(); } select = rbgSelect.valueInt; cpkPlayers[select].Show(); } } </syntaxhighlight> ==== ConfigOnChange ==== <code>ConfigOnChange</code> is called whenever <code>config</code> Dictionary is updated, mainly when Config Machine loads OptionInterfaces in IntroRoll, and when the user saves changes of configuration in ConfigMenu. Override this method to grab your configurable values. <code>config</code> Dictionary is where <code>UIconfig</code>’s value is stored. The following is an example of how to convert a string value to the corresponding type. <syntaxhighlight lang="csharp">public override void ConfigOnChange() { base.ConfigOnChange(); MyMod.config.myInt = int.Parse(config["keyInt"]); MyMod.config.myFloat = float.Parse(config["keyFloat"]); MyMod.config.myKey = OpKeyBinder.StringToKeyCode(config["keyKey"]); MyMod.config.myColor = OpColorPicker.HexToColor(config["keyColor"]); } </syntaxhighlight> ==== Signal ==== <code>Signal</code> is called when the user has interacted with <code>UItrigger</code>. Override this to have your OI to react. <syntaxhighlight lang="csharp"> public override void Signal(UItrigger trigger, string signal) { switch (signal) { case "reset": ConfigMenu.ResetCurrentConfig(); // This is the same as pressing Reset Config Button. break; } } </syntaxhighlight> === Generated OIs === <code>GeneratedOI</code> is a child class of <code>OptionInterface</code> that helps generating fixed-format GUI with less effort. <span id="displaying-basic-profile"></span> ==== Displaying Basic Profile ==== Simply inheriting <code>GeneratedOI</code> instead of <code>OptionInterface</code> works. This does make your mod dependent to Config Machine, and Config Machine generates GUI to display the basic information of your mod without this dependency. So this is only useful when you’re using OptionInterface for other features, like its Translation API. <syntaxhighlight lang="c#"> public class MyOI : GeneratedOI { private const string desc = "Changes this thing and that thing"; public MyOI() : base(plugin: MyPlugin.instance, desc) { transFile = "MyPlugin.Translation.txt"; } } </syntaxhighlight> The code above would generate a GUI like the following image: [[File:GeneratedOI-sample.png|thumb|none|alt=GeneratedOI Sample|GeneratedOI Sample]] You can also use its static method <code>AddBasicProfile</code> for basic profiles on top of the canvas. This also has an overload that accepts <code>OpScrollBox</code> instead of <code>OpTab</code>, if you have <code>OpScrollBox</code> replacing <code>OpTab</code>. <syntaxhighlight lang="c#"> public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; GeneratedOI.AddBasicProfile(Tabs[0], rwMod); Tabs[0].AddItems(new OpCheckBox(100f, 350f, "EnableStuff", false) { description = "Enables this stuff" }); } </syntaxhighlight> ==== BepInEx.Configuration ==== If you don't provide an OptionInterface, BepInEx can generate a simple config screen from your [[BepInPlugins|plugin]]'s config bindings (see <code>BepInEx.Configuration</code>). If this happens, CM will not create a separate file to store your config values. This method has upsides and downsides. * You don’t need to reference Config Machine in your project, and this doesn’t create a dependency for Config Machine. * The users can configure the plugin by opening the cfg file in Notepad outside the game. * However, you do not have control on detailed GUI design. First, we need <code>ConfigEntry</code> which you can bind to the <code>Config</code> property of <code>BaseUnityPlugin</code>. Consult [https://docs.bepinex.dev/articles/dev_guide/plugin_tutorial/4_configuration.html BepInEx Documentation] for farther detail. <syntaxhighlight lang="c#"> public static ConfigEntry<string> cfgText; public static ConfigEntry<bool> cfgCheck; void Awake() { cfgText = Config.Bind( "General", // section: defines which OpTab this will go "My Setting", // key: the name of setting "Hello, world!" // defaultValue "This is a description. It does things." // The description will be shown the right side of UIconfig // When you hover your mouse on UIconfig, // the first sentence will be displayed at the bottom of the screen ); cfgCheck = Config.Bind("General", "My Other Setting", true, "Another description is this."); } </syntaxhighlight> To access those settings, use <code>Value</code>. <syntaxhighlight lang="c#"> if (cfgCheck.Value) { Logger.LogMessage(cfgText.Value); } </syntaxhighlight> === Translation Support === While you can support translation for your mod on your own, Config Machine also offers translation solution. ==== Preparation ==== <code>OptionInterface</code> has a method called <code>Translate</code>, and when it's initially called, it will load specified (<code>transFile</code>) txt file from your assembly and make Dictionary depending on Rain World's language setting. In <code>BaseUnityPlugin.LoadOI</code> method, store the <code>OptionInterface</code> instance in somewhere before returning it. <syntaxhighlight lang="c#"> public static MyOI oi; public static MyOI LoadOI() { oi = new MyOI(); return oi; } </syntaxhighlight> Then make a static method that calls the translation method. <syntaxhighlight lang="c#">public static string Translate(string orig) { if (oi != null) { return oi.Translate(orig); } return orig; } </syntaxhighlight> Now when you need to translate something, you can pass your string through this method. ==== Writing Translation txt ==== Create a txt file that contains translation, too. Add txt file to your project, ''make sure'' that its encoding is <code>UTF-8</code>, then set it to be [Embedded Resources] for its compile setting. Then, in the constructor of your OptionInterface, set <code>transFile</code> to that resource name. If you have not put it in any folder, it's usually <code>&lt;ProjectName&gt;.&lt;TxtFileName&gt;.txt</code>, but you might get it wrong. If it's wrong when <code>OptionInterface.Translate</code> is initially called, Config Machine will log all the resources in your assembly in exceptionLog.txt so you can copy from it. <syntaxhighlight lang="c#">public MyOI() : base(plugin: MyPlugin.instance) { this.transFile = "MyPlugin.Translation.txt"; // if you do not know the resource name, just call Translate. // ConfigMachine will log all the resources in your assembly in exceptionLog.txt. } </syntaxhighlight> The format of the translation txt file for Config Machine is quite primitive. First, you add a keyword, then <code>|</code> for language separator, then language ID (<code>eng, ita, ger, spa, por, kor, jap, rus)</code>), <code>$</code> for another separator, then translation. If there is no translation, the translator will return the keyword, unless there is a translation for <code>eng</code>. (In that case, English "translation" will be used as default translation) The following is formatting example for txt file. <pre> // If the first two characters are '//', this line will be ignored. Nightcat Horn Colour|kor$¹ã°í¾çÀÌ »Ô »ö±ò // If you have variables, avoid using partial sentences. Not every language has the same subject-verb-object order. Press &lt;ThrowKey&gt; to stab.|kor$&lt;ThrowKey&gt; ¹öưÀ» ´­·¯ Â±â. // When translating the shorter-phrase, the translation might be sensitive with context, but English one does not. Duplicate key causes error(You can check exceptionLog.txt for duplicates), so you can set 'eng' translation for these cases. Property_as of possession|eng$Property|kor$¼ÒÀ¯¹° Property_as of quality|eng$Property|kor$¼Ó¼º // For line-breaks, use \n. (In code, it¡¯d be \\n) Each line represents a phrase, so you can¡¯t use actual line-break in a single chunk. LINE\nBREAK|kor$ÁÙ\n¹Ù²Þ</pre> ==== Running Translation ==== And here are some examples in code. Yes, running every text through the <code>Translate</code> method is tedious, but this is usually how it's done in Rain World or many other games. Make sure to check your mod in another language to confirm you haven’t missed any item. <syntaxhighlight lang="c#"> labelCpkrRadio.text = MyPlugin.Translate("Nightcat Horn Colour"); instance.room.game.cameras[0].hud.textPrompt.AddMessage(MyPlugin.Translate("Press <ThrowKey> to stab.").Replace("<ThrowKey>", k.ToString())); // k is variable in this example. labelLineBreak.text = MyPlugin.Translate("LINE\\nBREAK"); </syntaxhighlight> <!-- These aren't the part of tutorial but more of tips. This does not just apply for making Rain World mods but to general, whenever you're making something that supports translation. * When you have variables in your sentence, do not use partial phrases and Frankenstein it later with <code>string.Concat</code>. Not every language has the same grammar order of subject-verb-object as English. * Leave credits to the translators, since you¡¯re most likely getting volunteers from them. This is both good for showing gratitude to the translators and keeping the quality of the translation. The lack of credits equals a lack of responsibility. * Do not use machine translation. That usually hurts the user experience rather than enhancing it. --> == Acceptable Types == As of Config Machine <code>v1.5.1</code>, it accepts the following types and uses provided UIconfig. (Height is the pixel height that how much this ConfigEntry would use. And each entry get 20 pixeled gaps in between) {|class="wikitable" !align="right" width="23%"| type !align="center" width="29%"| UIconfig !align="right" width="23%"| Height !width="23%"| Note |- |align="right"| bool |align="center"| OpCheckBox |align="right"| 60 | |- |align="right"| byte |align="center"| OpSliderSubtle |align="right"| 90 | Range: [0, 20] |- |align="right"| uint |align="center"| OpSlider |align="right"| 90 | Range: [0, 100] |- |align="right"| int |align="center"| OpTextBox |align="right"| 60 | Accepts: Int |- |align="right"| float |align="center"| OpTextBox |align="right"| 60 | Accepts: Float |- |align="right"| string(Hex) |align="center"| OpColorPicker |align="right"| 170 | When defaultValue is Hex |- |align="right"| string |align="center"| OpTextBox |align="right"| 60 | When defaultValue is not Hex; Accepts: ASCII |- |align="right"| KeyCode |align="center"| OpKeyBinder |align="right"| 100 | |- |align="right"| enumType |align="center"| OpResourceSelector |align="right"| 60 | |- |align="right"| default |align="center"| N/A |align="right"| | Will warn the user that this plugin has ConfigEntry that’s not supported by Config Machine |} == Available UI Elements == Full list of available UI elements can be found [[ConfigMachine/Provided Elements|here]]. [[Category:Dependencies]] [[Category:Code Mods]] 030d016e658558f1201180da491aaf1dba4d98ce Level Editor 0 86 179 129 2022-08-10T19:56:46Z Dakras 6 wikitext text/x-wiki {{Cleanup}} == The Official Level Editor == [[File:editorFront.png|400px|thumb|right]] The Rain World level editor is a powerful tool that allows the creation of new rooms for the game, and editing existing rooms. It is the same editor the developers used to make all of the rooms for the base game. It takes specially formatted spritesheets and a number of programmed effects and outputs png files that the engine interprets in 3D (as well as an accompanying text file which contains collision and gameplay info). You can download the level editor from [https://ln.sync.com/dl/db7b0cf70/nebg7d6b-qg7gjua7-gjdi94jn-xuvivhw3/view/default/8384962820004 here.] There is also the Community Editor, which is a community-made edit of the original editor, with new features, bugfixes, and better ease of use. There is also Drizzle, a community made level renderer that's hardware accelerated. In the future it intends to replace the existing level editors. === Basic Features Overview === Once you've followed the on-screen instructions for either creating or opening a level, you are presented with the dashboard/preview screen. From here, you can switch between the different editors, load or save your level, and export it for use in-game. The preview presented here requires being manually updated whenever changes are made or when you first open a level. Pressing "1" at any point will bring you back to this screen so you can save your level or switch to a different editor. It's often best to start by modifying the dimensions of the room to your liking using the level size button before beginning to edit. You can change this at any time, but because you set the dimensions manually rather than visually, making changes later is more difficult and poses the risk of accidentally deleting a portion of your room if you aren't careful. From the dashboard you can switch to the Geometry Editor (for defining the level geometry and collision), the Tile Editor (for customizing the tiles and assets that make up the geometry created in the geometry editor), the Effects Editor (for adding procedural effects like erosion or slime, as well as things like plants or chains), the Light Editor (for customizing the light and shadow in your room), or the Prop Editor (for adding additional hand placed props and decals like graffiti). === Controls Overview === ==== View controls (numpad): ==== These are used for every editor view except the Camera and Environment editor to scroll around the screen. Notice, numlock must be turned on for these controls to have any effect. {| class="wikitable" |+ |- ! Key(s) !! Function |- | 8,2,4,6 || Moves view |- | 1 (hold) || Increases view scroll speed. |- | 3 (hold) || Increases view scroll speed even more. |- | 9 (hold) || Allow the view to move outside the boundaries of the level. |} ==== Menu keybinds (Number row): ==== These act as hotkeys to quickly switch between different editor views. These can be used in any editor view as well. {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | 1 || Main menu |- | 2 || Geometry |- | 3 || Tiles |- | 4 || Cameras |- | 5 || Light |- | 6 || Room size |} === Level Settings === ==== Level Size ==== This is where you change how big the level is. You can set the entire level size, and border tiles. Border tiles are padding around the room, mainly for resolutions that are larger than 4:3 It's recomended not to go under the defaults, or your final render will be cut off. ==== Default Medium ==== This determines if you can fall outside of the level or not, death pits still work the same either way however. ==== Light Type ==== The light type can either be set to '''ON''' which will use what you have done in the Light Editor, or '''OFF''' which paints everything in shadow. ==== Seed ==== This is the arrow on the fourth row of bars, which determines what seed the level will use. The seed determines random tile and prop placement, along with how effects are generated. === Rendering === ==== Prioritize Cam ==== This determines what camera will be rendered first, before starting from the beginning. Very useful for re-rendering a specific screen. ==== Text Output ==== This outputs a .txt of the level's geometry, usable in-game. ==== Render Level ==== This renders the screens ==== Mass Render ==== This will render every level in the selected folder. === Editors === <tabber> |-|Geometry Editor= == Geometry Editor == [[File: geoEditor.png|400px|thumb|right]] The Geometry Editor is the first stop for the creation of new rooms. In the Geometry Editor, you define the gameplay and collision information of your room, such as the placement of vertical and horizontal bars, shortcuts, room entrances, creature dens, and garbage worm placement. (to connect your room to other rooms), and a number of other gameplay relevant elements. === Controls === {| class="wikitable" |+ Geometry editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | Arrow keys || Primary cursor scroll through toolbox. If mouse over the toolbox, mouse moves cursor instead. |- | Mouse || Primary cursor movement. |- | LMB || Primary cursor use current tool. |- | Q (hold) || Secondary cursor scroll through toolbox. |- | E,S,D,F || Secondary cursor movement. |- | W || Secondary cursor use current tool. |} As an experimental feature, the developers implemented a second cursor and control scheme to allow two users to edit a room simultaneously (with the second user entirely on the keyboard). While this ended up being a little used feature (as far as we are aware), it is still implemented in the current editor (represented by the grey cursor). == Toolbox == {| class="wikitable" |+ Level Editor Geo Tools |- | Inverse || Flips the currently selected tile between walls, and air. |- | Paint Walls || Paints solid tiles. |- | Paint Air || Paints non-solid tiles. |- | Make Slope || Paints a slope, these can only be placed inside corners, and as the edges of larger solids. |- | Make Floor || Paints thin platforms that you can stand on, but also hold down to fall through. |- | Rect Wall || Paints solid tiles in a rectangle. Click two points to set the rectangle's dimensions and paint. |- | Rect Air || Same as above, except for non-solid tiles. |- | Worm Grass || Placed above solid ground to spawn worm grass tendrils. The number placed together to the left and right decides the height of the grass. |- | Crack Terrain || Renders as a roughly cracked fissure through the material painted on it in the tile editor. Slugcat can crawl through these tunnels. An example in the vanilla game is in the western temple styled area of the subterranean. Where there are fissures to travel beneath certain stone statues. |- | Horizontal Beam || Climbable pole. Slugcat can only climb these on layer 1. |- | Vertical Beam || Same as above, except in the other direction. |- | Glass Wall || Paints invisible solid walls. |- | Waterfall || Will cause a waterfall to appear in game, with this tile at the top of it. |} {| class="wikitable" |+ Level Editor Item and Batfly Tools |- | Place Rock || A Rock will spawn at this location with a 60% chance. |- | Place Spear ||A Spear will spawn at this location with a 60% chance. |- | Spawn Fly || Does nothing. |- | Forbid Fly Chains || Prevents bat flies from hanging together in specific locations to rest. |- | Hive || Places a bat fly hive. Bat flies can use these to quickly travel to different parts of a room. |} === Short Cuts and Entrances === [[File: geoShortcuts3.png|200px|thumb]] [[File: geoShortcuts1.gif|200px|thumb]] [[File: geoShortcuts2.png|200px|thumb|right]] {| class="wikitable" |+ Level Editor Shortcut Tools |- | Short Cut Entrance || Places the entrance of a short cut into the room. Please see the tips and tricks section for details of how to properly connect entrances and doors together. |- | Short Cut || Places a short cut's travel dot. These go between short cut entrances, and specific entrance or den tiles. |- | Dragon Den || Places a creature nest. These can be configured to spawn creatures in a region using the region's World File. |- | Entrance || Used to connect between rooms. Slugcat can use these short cuts as doors to different rooms. This is configured in the regions world file. |- | Scavenger Hole || Attaches to short cut entrances like dens do, and allows scavengers to quickly travel to this room as they wander through a region. |- | Whack-A-Mole-Hole || Attaches to short cut entrances like dens do, and allows creatures to quickly travel around a room. Green lizards use these very often. |- | "G" || Garbage worm den. Attaches to short cut entrances like normal dens do. These dens are specific to garbage worms, and cannot be entered by other creatures. They are required by garbage worms to properly function. Linking them to normal dens will cause errors and strange behavior. You will still need to assign the worms to the den in the regions world file. |} Short cuts and their connections to the various kinds of entrances in Rain World have specific needs! Improperly making the short cut can lead to crashes, or odd behavior in game. This gif presents several examples of properly linked short cuts. A short cut dot is not required between the short cut's entrance, and the den or door it is connecting to. However, the shortcut must show as an arrow toward the den or door for the link to it to be proper. The short cut entrance also requires walls surrounding it on all sides, with the exception of the side you will enter it from. Connecting two short cut entrances to each other with dots will connect them as a tunnel between the two. The various other den and entrance types will decide how enemies interact with the entrance. Dens are used for most normal creatures. Scavenger require their unique entrance type to enter the room properly without using normal doors. ( They will not be able to leave the OFFSCREEN room of the region if there are no scavenger doors at all in the region! ) Garbage worms require a unique door due to their AI's behavior, and cannot use normal dens, nore can enemies enter their dens. Finally the Whack-A-Mole holes are used by creatures to warp from various short cuts around the room. The images on the right also display the bare minimum needed for short cut entrances to function, and example doors in all directions. === Layer Info === {| class="wikitable" |+ Level Editor Layer and Misc Tools |- | Copy Backwards || Copies a rectangle of tiles on the current layer to the next layer. This does not wrap around back to layer 1 if you are on layer 3. |- | Work Layer || Changes layers from 1 to 3 and then back to 1. |- | Clear All || Selects a rectangle that resets all tiles inside it, on all layers, back to open air. |- | Toggle Mirror || Turns on and off a mirror tile painting mode. What you do on one side of the mirror will be copied on the other. |- | Move Mirror || Allows you to move the location of the Mirror. |- | Move Level || Moves the whole level in a certain direction. Place the mouse cursor outside the level, then use the arrow keys to move the level in the direction you want. It will not work if your mouse is inside the level as using the arrow keys will swap to another tool. |- | Empty || Does nothing. Good to set as your tool if you have to tab out, as it does nothing. |} Rain World levels consist of 3 layers, each representing a different depth. This layer info is represented visually through the color of tiles, and you can switch between editing on different layers with the work layer tool in the bottom left of the tool panel. Layer 1 draws in full black, layer 2 draws in green, and layer 3 draws in red. These colors will blend if multiple layers are drawn on top of each other. Layer 1 is the foreground, and any filled tiles on this layer will have collision. This is the base layer you define for the sake of gameplay, as any air here is space you can traverse. Layer 2 is the midground, which you can imagine as the back wall of your room. Wall climbing creatures also interact with this. Layer 3 is the extreme background, behind the back wall of the room (for placing distant objects or giving the room a section of open sky). Nothing interacts with this at all. Note: The tile editor defines the visual tiles and props that make up this geometry, so in order to place solid objects in the tile editor (on any layer), those tiles need to be filled here in the geometry editor. Even though the mid-ground and background do not provide any collision geometry, in order to place solid props on those layers the tiles need to be filled here in the geometry editor. Similarly, some props can only be placed on air on the layers (like fences). === Tips and Tricks === - Many of the gameplay features require that they be placed within the margins of your room (represented by the white border). An entrance or creature den placed outside of your margins will render your room un-enterable at best, and crash the game at worst. Short Cut Entrances and Short Cuts can be placed outside the level boundary just fine, however. - Border tiles are tiles that can't be interacted with, and are there for looks only. The room will copy the last tile from the border forever in that direction so be careful with your geometry, or you'll be able to walk out of bounds through "solid" walls or stand in the air. - Because the tool panel loops around from top to bottom and left to right, when editing the base geometry (walls and air) it's faster to use the arrow keys to go up to reach the work layer tool to swap layers than to cycle through the whole list to reach them. Also, the rectangular wall and air tools will let you edit large chunks of your level much faster than going tile by tile. - Because the layers move with a parallax effect, it's often necessary to extend elements on your background layer behind your other layers, otherwise the camera angle will sometimes let you see a gap to the left or right of a background wall and the layer in front of it (for example). It can be just a few tiles extended, unless you have tiles infront that are transparent and reveal behind it. |-|Tile Editor= Full article here [[Tile Editor]]. {| class="wikitable" |+ Tile editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Select tile category |- | W,S || Select tile in current category |- | LMB || Place tile under cursor |- | RMB || Erase tile under cursor |- | F (hold) || Use a 3x3 brush for materials |- | V (hold) || Use a 5x5 brush for materials |- | Tab+x+c || Clears all tiles |- | L || Change active layer (1, 2, 3, loop back to 1) |- | E || Sets default material of the room to the currently selected material |- | F (hold) || Enables force placing selected tile (ignoring geometry, erasing colliding tiles) |- | G (hold) || Enables force placing selected tile (forcing appropriate geometry for the tile, erasing colliding tiles) |- | Q || "Eyedropper" (selects tile/material hovered over) |} |-|Effect Editor= Full article here [[Effects Editor]]. {| class="wikitable" |+ Effect library keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Select effect category |- | W,S || Select effect in current category |- | E || Switches to editing applied effects |- | Space || Adds selected effect to the stack |} {| class="wikitable" |+ Applied effect keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,S || Scroll through the effect stack |- | N || Switch to effect library |- | Space || Edit selected effect in the stack |} Effect editing: {| class="wikitable" |+ Effect editing keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Scroll through options in the effect's menu |- | W,S || Changes the current effect's menu |- | Space || Activates selected option in the effect's menu |- | LMB || Paints effect in the level |- | RMB || Erases effect in the level |- | R || Brush size up |- | F || Brush size down |- | E || Switch to effect stack |- | N || Switch to effect library |} |-|Camera Editor= Full article here Camera Editor. N - New camera, spawns held by mouse E - grab a camera if none is held D - Delete held camera P - Place held camera |-|Light editor= Full article here [[Light Editor]]. {| class="wikitable" |+ Light editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,A,S,D || Scale current light shape |- | Q,E || Rotate current light shape |- | Z || Toggle between drawing and erasing light |- | LMB || Paint light |- | RMB (hold) || Rotate light shape in direction of mouse ( does not paint it.) |- | R,F || Scroll through light shape library |- | J,L || Change angle of light source |- | I,K || Change distance of light source |} |-|Prop Editor= Full article here [[Prop Editor]]. {| class="wikitable" |+ Prop editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A, D || Changes prop library's category |- | W, S || Scrolls through props in current category |- | LMB || Place current prop |- | V (hold) || LMB erases highlighted prop |- | Q,E || Rotate prop left and right |- | Space (hold) || Speed up rotation |- | Y,G,H,J || Stretch prop |- | T || Reset prop stretching |- | R || reset stretching, and rotation |- | Y, H || (on wire/tube props) increases or decreases prop's physics node count. Less means more taught, more means more loose |- | X || Pause wire/tube physics |- | Tab+X+C || clear all props |- | B || Click mouse left to set the highlighted prop as the currently selected prop |- | L || Change layer |- | RMB || Cycle depth in current layer (10 sublevels). |- | Space + RMB || Cycle depth in current layer, reverse direction. |- | U,I,O,P (hold) || Freeform stretch by one of the corners (U - top right, I - bottom right, O - bottom left, and P - top left.) |- | K || resets freeform stretching. |- | N || Switches to editing properties menu of the prop. Things like forcing certain graffiti to be drawn instead of a random one. |- | M (hold) || LMB opens properties of an already placed prop instead of placing a prop (same menu as above) |- | Z || Changes prop color |- | F + LMB/RMB || Changes between prop variants. This only applies to certain props. |} |-|Environment Editor= {| class="wikitable" |+ Environment editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | L || Set water level to mouse pointer |- | F || Toggles between drawing water above the first layer or below it. |- | W || Toggle water on level |} </tabber> == Crash Avoidance and Editor Quirks == Due to the editor being extremely user unfriendly, you are likely to run into various crashes without warning. This is a list of various things to avoid doing. === Crashes: === Do not switch to editing applied effects in the Effects Editor when there are none. The switch will be invisible, and attempting to use the space bar to select something from there will crash the Level Editor. Some effects have very specific conditions and cause issues when rendering, Effects include: Thick Roots, and Shadow Plants. these ones can be okayed through until it renders.) Be sure to remove tiles from parts of a room that will be removed if you resize the room to cut those areas out, those tiles are still recorded, and will crash renders instantly. props are the exact same as above Never render with no cameras. It will crash. Always move the prop menu into an actual category when you open it, it keeps the last menu used, and crashes if you select any entry that is not a real prop. (EX: it will have the effects menu, or tile menu.) If you are using the Mirrored tile placer, in the geometry editor. Placing poles, with the other side of the mirrored brush being outside of the room, will crash the editor. === Quirks: === The main menu is a mess when you return from using the Light Editor or the Environment Editor. Just change to any other editor (geometry or tiles, and back to main menu) to clean it. This is not a crash, but will help prevent confusion if you know to expect this. To use the Move and Move Mirror tools in the editor, you must first select them, and then move your mouse outside of the room itself, before it will respond to your inputs. Usually you will only need to put your mouse over the editor, but in larger rooms, this is often an issue, as the room is "behind" the menu, and thus only changes tool selection. The editor still receives inputs if you only tab out using alt-tab. When viewing another window, it's important to always minimize the editor, because there are many things that can go wrong if you're randomly clicking in the editor. (Requires more confirmation) The screen during rendering should usually show the map being rendered, but it may not. In the task manager, The Rain World Editor is under the tab Adobe Projector. Sometimes the reason it is not showing is a second application called "Print driver host for applications". Closing the application seems to fix the issue. The window for the application may be too big to fit on screen, and cannot be fixed since reaching the top bar or right clicking cannot be accessed to move the window. === Demo and Tutorial Videos === Region Developer Kaeporo created a tutorial for creating levels in and out of the level editor: {{#ev:youtube|YQ0DO-fmPCE|||||urlargs=""}} Mod community member Sacretis also put together a demonstration video, this time covering the creation of a room from scratch to visual polish (massively sped up for the sake of time): {{#ev:youtube|sEE3X1izaJA|||||urlargs=""}} ade1d714eced70597b8bdb6a146cc1ea094f39dc Template:Cleanup 10 88 180 93 2022-08-10T20:00:35Z Thalber 3 Make {{Cleanup}} autocategorize wikitext text/x-wiki <includeonly><div class="nomobile">{{Ambox | image = <p><span style="margin-right:15px>[[File:Hardhatcat.png|middle]]</span> | type = '''This article needs clean-up to meet quality standards.''' | info = Our community is working hard to rehaul this page. In the meantime, feel free to help {{fullurl|{{FULLPAGENAME}}|action=edit{{#if: {{{1|}}} | &section={{{1}}} }}|text=improve}} what's currently written.</p> | border = gray }}</div> [[Category:Cleanup needed]] </includeonly> <noinclude> Usage: <nowiki>{{Cleanup}}</nowiki> {{Cleanup}} </noinclude> 18f4c27dedc5058fc6f398bb58ad1026a18ce3ef Category:Cleanup needed 14 116 181 2022-08-10T20:03:09Z Thalber 3 Created page with "This category contains pages that have <nowiki>{{Cleanup}}</nowiki> template and need further improvements." wikitext text/x-wiki This category contains pages that have <nowiki>{{Cleanup}}</nowiki> template and need further improvements. 672b36a287337ae004f476d6ef84c20fe8e1a288 Category:Dependencies 14 117 182 2022-08-10T20:06:16Z Thalber 3 Created page with "This category contains pages about common useful dependency mods/libraries. [[Category:Code Mods]]" wikitext text/x-wiki This category contains pages about common useful dependency mods/libraries. [[Category:Code Mods]] 4eb14edf005badae647208fa10b5acc114fbfbc7 EnumExtender 0 94 183 144 2022-08-10T20:07:23Z Thalber 3 wikitext text/x-wiki {{Cleanup}} '''[https://beestuff.pythonanywhere.com/audb/api/mods/0/1/download/latest EnumExtender]''' or '''EE''' is a tool mod which allows adding entries to <code>Enum</code>s. It is widely used as a dependency library. == Features == === Automatic extension === ''Using this feature does not require referencing EE assembly in your project.'' On initialization, EE scans all loaded classes, looking for <code>public static class</code> with names starting with <code>EnumExt_</code>. Extensions are created from <code>public static</code> fields with the type of target enum. Created entries have the same name as the field, and the field gets the value of the new entry. Example use: <syntaxhighlight lang="csharp"> public static class EnumExt_MyMod { // You can have multiple EnumExt_ classes in your assembly if you need multiple items with the same name for the different enum //this adds entry "Vultures" to enum "CreatureCommnuities.CommunityID" public static CreatureCommnuities.CommunityID Vultures; //this adds "YellowishWhite" to "SlugcatStats.Name" public static SlugcatStats.Name YellowishWhite; public static SlugcatStats.Name WhitishYellow; } </syntaxhighlight> To access these new enum items, instead of <code>[enum].[item]</code>, use that static field. To compare it, use <code>if</code> statements (unfortunately, you can not use static fields for branches in a <code>switch</code> statement). Example use: <syntaxhighlight lang="csharp"> public static SlugStatsPatch(On.SlugcatStats.orig_ctor orig, SlugcatStats stats, int slugcatNumber, bool malnourished) {     orig.Invoke(stats, slugcatNumber, malnourished);     if (stats.name == EnumExt_MyMod.YellowishWhite)     {         stats.runspeedFac = 1.2f;         stats.poleClimbSpeedFac = 1.25f;         stats.corridorClimbSpeedFac = 1.2f;     } } </syntaxhighlight> However, if EnumExtender is not present in runtime (for instance, the user forgot to install EnumExtender), these fields won't be initialized and will always stay at 0. This can be used to easily detect whether EnumExtender is installed or not. <syntaxhighlight lang="csharp"> public static bool HasEnumExt => (int)EnumExt_MyMod.YellowishWhite > 0; // This property returns true after EE initializes (after OnEnable) </syntaxhighlight> ==== Switch statement workaround ==== If you have multiple new items and really want to use switches, you can do something like the following: <syntaxhighlight lang="csharp"> public static class EnumSwitch { //the intermediary enum     public enum SlugcatStatsName     {         DEFAULT = -1, // unrelated to this mod         YellowishWhite,         WhitishYellow     };     public static SlugcatStatsName GetSlugStatsNameInterm(SlugcatStats.Name name)     {         if (!HasEnumExt) { return SlugcatStatsName.DEFAULT; } // EnumExt is not installed         if (name == EnumExt_MyMod.YellowishWhite) { return SlugcatStatsName.YellowishWhite; }         if (name == EnumExt_MyMod.WhitishYellow) { return SlugcatStatsName.WhitishYellow; }         return SlugcatStatsName.DEFAULT;     } } </syntaxhighlight> And when you need to use switch later, <syntaxhighlight lang="csharp"> switch (EnumSwitch.GetSlugStatsNameInterm(name)) {     default:     case SlugcatStatsName.DEFAULT: break;     case SlugcatStatsName.YellowishWhite:         break;     case SlugcatStatsName.WhitishYellow:         break; } </syntaxhighlight> <!--ehhhh this was a bad idea '''Alternatively''', if you want to use one switch statement containing checks for both vanilla and intermediary enum, you can # give an explicit value to the interm enum, ideally some really large numbers so that it doesn't collide with any vanilla values # modify interm method (<code>GetSlugStatsNameInterm</code> in the example) to return an int and return original value as int when EE is not installed # instead of switching over <syntaxhighlight lang="charp"> //... //... </syntaxhighlight> --> === Manual extension === ''Using this feature requires referencing EE assembly in your project.'' This method is useful when you don't know what name your new entries will have to have. It is more cumbersome to use and less safe, but # Ensure that EE has been initialized. You can either wait until the <code>EnumExt_</code> get appropriate values, or call <code>PastebinMachine.EnumExtender.EnsureInit()</code> # Call <code>PastebinMachine.EnumExtender.AddDeclaration(Type, string)</code> one or more times. First parameter is <code>Type</code> of the enum, second is the name of new entry. '''Ensuring there are no name collisions is on you!''' # Call <code>PastebinMachine.EnumExtender.ExtendEnumsAgain</code> ''once'' to register all your new enums. '''NOTE''': Last step may have a noticeable overhead, and each call to <code>ExtendEnumsAgain</code> causes a small but permanent memory leak. Do not overuse. <code>ExtendEnumsAgain</code> does not return the added values, you have to obtain them manually through <code>Enum.GetNames()</code> or <code>Enum.GetValues()</code>. Storing the resulting values correctly is the user's responsibility. == Summary == Both modes allow you to use methods like <code>Enum.Parse</code> with extended values freely. RW codebase uses enums pretty much everywhere, so EnumExtender is a often a vital dependency. [[Category:Code Mods]] [[Category:Dependencies]] f407d36dc154c639dbe1fa12a27add60d958534b ConfigMachine/Provided Elements 0 118 187 2022-08-10T20:29:16Z Thalber 3 Port CM elements page wikitext text/x-wiki {{Cleanup}} This page is '''unfinished''' and needs to be expanded. This page contains a list of UIElements provided by default with [[ConfigMachine]]. Up to date with Config Machine <code>v1.5.1</code>. This page explains what each provided <code>UIelement</code> is and how to use them. You can check out the source code of Config Machine from its [https://github.com/metnias/CompletelyOptional github page], or have <code>ConfigMachine.xml</code> in your Reference folder for summaries. However, there are functions left unused (mainly because the modders are unaware) so this page will cover them. Some provided <code>UIelement</code>s have <code>fixedSize</code>, which prevents it being resized. The list of those follows: {|class="wikitable" ! UIelement !align="right"| width !align="right"| height |- | OpCheckBox |align="right"| 24 |align="right"| 24 |- | OpRadioButton |align="right"| 24 |align="right"| 24 |- | OpDragger |align="right"| 24 |align="right"| 24 |- | OpSlider |align="right"| **30* |align="right"| |- | OpSliderSubtle |align="right"| **30* |align="right"| |- | OpComboBox |align="right"| |align="right"| 24 |- | OpColorPicker |align="right"| 150 |align="right"| 150 |- | OpTextBox |align="right"| |align="right"| 24 |- | OpHoldButton |align="right"| rad: |align="right"| ''55'' |} (* The width perpendicular to its length is fixed) == UIelement == UIelement is everything that can be added in <code>OpTab</code>, which is 600x600 canvas. Its sub-categories are [[##UIconfig|UIconfig]] and [[##UItrigger|UItrigger]]. UIelement can be either rectangular (pos and size) or circular (pos and rad), although the vast majority of provided UIelements are rectangular. (''Italic'' properties call <code>OnChange</code> when modified) {|class="wikitable" !width="50%"| Property !width="50%"| |- | ''pos(setter)'' | Sets bottom-left position ''relative'' to its canvas (<code>OpTab</code>/<code>OpScrollBox</code>). |- | ''size'' | The size of the element. (When this is rectangular) |- | ''rad'' | The radius of the element. (When this is circular) |- | description | Infotext that will be shown at the bottom of the screen when MouseOver is true. |- | MouseOver | Whether the mouse cursor is over this element. |} {|class="wikitable" !width="50%"| Method !width="50%"| |- | Hide() | Hides this UIelement, and prevent interaction. |- | Show() | Unhide this UIelement. |- | GetPos() | Returns bottom-left position ''relative'' to its canvas (<code>OpTab</code>/<code>OpScrollBox</code>). (pos(getter) returns ''absolute'' position) |- | Reset() | Reset this UIelement if it’s possible. |- | FrameMultiply(origFrameCount) | (static) When you have a frame counter in Update, use this to accommodate with Many More Fixes’ FPS unlock feature. |- | DTMultiply(deltaTime) | (static) Without MMF’s FPS meddling, this returns somewhere close to <code>1f</code>. Use this for ticking gradual changes. |} === OpLabel === [[File:Label.png|thumb|none|alt=OpLabel Sample|OpLabel Sample]] Simply displays text. (''Italic'' parameters are optional) {|class="wikitable" !width="50%"| Constructor Parameter !width="50%"| Displays text aligned to defined rectangular |- | pos | BottomLeft position relative from the canvas origin. |- | size | Width and height of the rectangle this UIelement occupies. |- | ''text'' | Text to be displayed. Setting it empty will generate Lorem Ipsum for testing. |- | ''alignment'' | Horizontal alignment, whether the text is aligned to left, center, right with the rectangle defined its size. |- | ''bigText'' | Whether to use the bigger font or not. |} {|class="wikitable" !width="50%"| Constructor Parameter !width="50%"| Displays text that goes right from the position |- | posX | Relative distance from the canvas origin to the left side of the UIelement. |- | posY | Relative distance from the canvas origin to bottom side of the UIelement. |- | ''text'' | Text to be displayed. Setting it empty will generate Lorem Ipsum for testing. |- | ''bigText'' | Whether to use the bigger font or not. |} {|class="wikitable" !width="50%"| Property !width="50%"| |- | ''text'' | Text to be displayed. |- | autoWrap | If true, when the text goes over its width, a linebreak will be inserted. |- | ''alignment'' | Horizontal alignment, whether the text is aligned to left, center, right with the rectangle defined its size. |- | ''verticalAlignment'' | Vertical alignment, whether the text is aligned to top, center, bottom with the rectangle defined its size. |- | bumpBehav | <code>null</code> by default. Setting this to other bumpBehaviour will synchronize highlighting. Creating new BumpBehaviour with this label turns itself reactive. |- | color | Colour of the text. |} ==== OpLabelLong ==== A child class of [[###OpLabel|<code>OpLabel</code>]] that is specialized for displaying a long wall of text. This will always use the smaller font. {|class="wikitable" !width="50%"| Constructor Parameter !width="50%"| |- | pos | BottomLeft position relative from the canvas origin. |- | size | Width and height of the rectangle this UIelement occupies. |- | ''text'' | Text to be displayed. Setting it empty will generate Lorem Ipsum for testing. |- | autoWrap | If true, when the text goes over its width, a linebreak will be inserted. |- | ''alignment'' | Horizontal alignment, whether the text is aligned to left, center, right with the rectangle defined its size. |} {|class="wikitable" !width="50%"| Property !width="50%"| |- | allowOverflow | If it’s false, text that goes over the height will be discarded. |} === OpRect === [[File:Rect.png|thumb|none|alt=OpRect Sample|OpRect Sample]] Simple rectangular, useful to make a boundary to group UIelements. Z-order is the order they’re initialized, so for that purpose, initialize OpRect beforehand. {|class="wikitable" ! Constructor Parameter ! |- | pos | BottomLeft position relative from the canvas origin. |- | size | Width and height of the rectangle this UIelement occupies. |- | ''alpha'' | Alpha of the background of the rectangle. |} {|class="wikitable" !width="50%"| Property !width="50%"| |- | colorEdge | The colour of boundary sprites. |- | colorFill | The colour of fill sprites. |- | alpha | Alpha of the background of the rectangle. If doesBump, this gets ignored. |- | doesBump | If true, this rectangle reacts to mouse cursor hovering . |- | bumpBehav | If doesBump, this controls reaction. If not, this stays <code>null</code>. |} === OpImage === [[File:Image.png|thumb|none|alt=OpImage Sample|OpImage Sample]] Displays an image, whether it’s <code>FAtlasElement</code> that’s already loaded in <code>Futile.atlasManager</code>, or <code>Texture2D</code>. {|class="wikitable" ! Constructor Parameter ! Displays Texture2D |- | pos | BottomLeft position relative from the canvas origin. |- | image | Texture2D image to be displayed. |} {|class="wikitable" ! Constructor Parameter ! Displays FAtlasElement |- | pos | BottomLeft position relative from the canvas origin. |- | fAtlasElement | The name of FAtlasElement. |} {|class="wikitable" !width="50%"| Property !width="50%"| |- | ''color'' | The colour of the sprite. |- | ''anchor'' | The anchor of the sprite. (0f, 0f) to set pos as BottomLeft, and (0.5f, 0.5f) to set pos as the centre. |- | ''scale'' | The scale of the sprite. |- | ''alpha'' | The alpha of the sprite. |} You can change the image without making new OpImage. However, you cannot change the Texture2D version to FAtlasElement and vice versa. {|class="wikitable" ! Method ! |- | ChangeImage(newImage) | Swap image to new Texture2D. |- | ChangeElement(newElement) | Swap FAtlasElement to new one. |} === OpScrollBox === OpScrollBox is written by Slime_Cubed. It’s a special UIelement that acts as a canvas, like OpTab. [[File:ScrollBox_Box.png|thumb|none|alt=OpScrollBox Sample - Box|OpScrollBox Sample - Box]] {|class="wikitable" ! Constructor Parameter ! Rectangular ScrollBox inside OpTab |- | pos | BottomLeft position relative from the canvas origin. |- | size | The size of the display. |- | contentSize | Internal length of the scroll direction. |- | ''horizontal'' | Whether this scrolls horizontally or vertically. |- | ''hasBack'' | Whether its boundary will have filled backdrop or not. |- | ''hasSlideBar'' | Whether this will have a scrollbar or not. |} [[File:ScrollBox_Tab.png|thumb|none|alt=OpScrollBox Sample - Tab|OpScrollBox Sample - Tab]] {|class="wikitable" ! Constructor Parameter ! ScrollBox that replaces OpTab |- | tab | BottomLeft position relative from the canvas origin. |- | contentSize | The size of the display. |- | ''horizontal'' | Whether this scrolls horizontally or vertically. |- | ''hasSlideBar'' | Whether this will have a scrollbar or not. |} Think of OpScrollBox as a window that displays a larger canvas inside. The size of this window is the same as <code>size</code>. The size of the canvas inside has <code>contentSize</code> for its scroll-direction length, and the other length matches the width of this window. [[File:ScrollBox_Diagram.png|thumb|none|alt=OpScrollBox Diagram|OpScrollBox Diagram]] The diagram above would be coded like the following. Their <code>pos</code> is relative to the bottom left origin of the canvas inside the OpScrollBox. The result of this code is shown above. <syntaxhighlight lang="c#"> OpScrollBox scb = new OpScrollBox(new Vector2(100f, 100f), new Vector2(240f, 150f), 400f); Tabs[0].AddItems(scb); // Not required if you're using Tab version of constructor scb.AddItems(new OpLabelLong(new Vector2(20f, 20f), new Vector2(120f, 200f)), new OpSlider(new Vector2(160f, 30f), "_", new IntVector2(-20, 20), length: 180, true, 10)); // Use AddItems on OpScrollBox instead of OpTab </syntaxhighlight> {|class="wikitable" !width="50%"| Property !width="50%"| |- | redrawFlags | When this ScrollBox should be redrawn. Never / Always(default) / OnHover / OnKeypress. |- | colorEdge | Edge colour of rectangles. |- | colorFill | Fill colour of rectangles. |- | fillAlpha | Fill alpha of boundary rectangle. |- | doesBackBump | If false, the boundary rectangle does not react with mouseover. |- | ScrollLocked | Whether the scrolling is locked. Manipulated by <code>Lock</code> and <code>Unlock</code> method. |- | ScrollOffset | The visual offset, in pixels, of the contents of this ScrollBox. (&lt;=0) |- | MaxScroll | The value of <code>ScrollOffset</code> at the topmost or rightmost position of the box. (&lt;=0) |- | targetScrollOffset | The target value of <code>ScrollOffset</code>. Change this to smoothly animate scrolling. |} {|class="wikitable" !width="50%"| Method !width="50%"| |- | AddItems(items) | Adds a collection of items to the interior of this ScrollBox. Use this instead of <code>OpTab.AddItems</code> for its children. |- | Lock(stopImmediately) | Locks scrolling. If <code>stopImmediately</code>, ignore <code>targetScrollOffset</code> and stops immediately. |- | UnLock() | Unlocks scrolling. |- | ScrollToTop(''immediate'') | Scrolls to the top/leftmost. If <code>immediate</code>, scrolling animation gets cancelled. |- | ScrollToBottom(''immediate'') | Scrolls to the bottom/rightmost. If <code>immediate</code>, scrolling animation gets cancelled. |- | MarkDirty() | Forces redrawing at the end of this frame. |- | MarkDirty(time) | Forces redrawing for the amount of <code>time</code> in seconds. |} === OpContainer === This is an easy-to-access FContainer for ConfigMenu. {|class="wikitable" ! Constructor Parameter ! |- | pos | The origin of this element relative to the canvas origin. |} {|class="wikitable" !width="50%"| Property !width="50%"| |- | container | Accessible FContainer. You can access this without checking isOptionMenu. (NullRef-proof) |} == UIconfig == <code>UIconfig</code> is a subcategory of [[##UIelement|UIelement]], and has few extra properties and methods. Their value gets saved in <code>ModConfigs</code> folder in json format. If the key is either <code>null</code>, Empty, or starts with <code>_</code>, it is considered <code>cosmetic</code> and its value won’t be saved. For collecting config values, access <code>config</code> dictionary with <code>key</code> you’ve set, in <code>ConfigOnChange</code>. {|class="wikitable" !width="50%"| Property !width="50%"| |- | key | (readonly) Unique key to save and access the value. |- | ''value'' | The value that gets saved. <code>valueInt</code>, <code>valueFloat</code>, and <code>valueBool</code> exist which is useful for designing reactive GUI. |- | greyedOut | If true, the element gets greyed out visually and cannot be interacted with. |- | bumpBehav | <code>BumpBehaviour</code> instance this UIconfig has. |} {|class="wikitable" ! Method ! |- | ForceValue(newValue) | Change <code>value</code> without invoking <code>OnChange()</code>. |} === OpCheckBox === [[File:CheckBox.png|thumb|none|alt=OpCheckBox Sample|OpCheckBox Sample]] [https://en.wikipedia.org/wiki/Checkbox CheckBox] (a.k.a. TickBox) permits the user to make a binary choice. This returns bool (<code>&quot;true&quot;</code> or <code>&quot;false&quot;</code>). Its size is fixed to 24x24. {|class="wikitable" ! Constructor Parameter ! Default constructor |- | pos | BottomLeft position relative from the canvas origin. |- | key | Unique key to save and access the value. |- | ''defaultBool'' | Default value. |} {|class="wikitable" !width="50%"| Constructor Parameter !width="50%"| Lazier version that accepts two float for pos |- | posX | Relative distance from the canvas origin to the left side of the UIelement. |- | posY | Relative distance from the canvas origin to bottom side of the UIelement. |- | key | Unique key to save and access the value. |- | defaultBool | Default value. |} {|class="wikitable" ! Property ! |- | colorEdge | The colour of its boundary and its symbol. |- | colorFill | The colour that fills inside. |} === OpRadioButtonGroup === [[File:RadioButton.png|thumb|none|alt=OpRadioButton Sample|OpRadioButton Sample]] [https://en.wikipedia.org/wiki/Radio_button RadioButton] (a.k.a. OptionButton) permits the user to choose only one of a predefined set of mutually exclusive options. <code>OpRadioButton</code> is ''UIelement'' that ''looks'' like an UIconfig, but isn’t. <code>OpRadioButtonGroup</code>, albeit invisible, is what actually stores the value to be saved. This returns int value. As OpRadioButtonGroup is arbitary, it doesn’t need the <code>pos</code> to be initialized. However, if your OpRadioButtons should be in OpScrollBox, add OpRadioButtonGroup for its child instead of OpTab. {|class="wikitable" ! Constructor Parameter ! Default constructor |- | key | Unique key to save and access the value. |- | ''defaultValue'' | Default value. 0 or higher. |} {|class="wikitable" !width="50%"| Method !width="50%"| |- | buttons | OpRadioButtons that belong to this. Use SetButtons(buttons) to set. |} {|class="wikitable" !width="50%"| Method !width="50%"| |- | SetButtons(buttons) | Binds OpRadioButton to this. This also adds <code>OpRadioButton</code>s to the canvas this is in. |- | Hide() | Calls Hide() for all children. |- | Show() | Calls Show() for all children. |- | SetColorEdge(newColor) | Changes colorEdge of all children. |- | SetColorFill(newColor) | Changes colorFill of all children. |} Example: <syntaxhighlight lang="c#"> OpRadioButtonGroup group = new OpRadioButtonGroup("MyOption"); Tabs[1].AddItems(group); // Add this to canvas before calling SetButtons group.SetButtons(new OpRadioButton[] { new OpRadioButton(300f, 450f), new OpRadioButton(350f, 450f) }); // SetButtons adds params to the canvas the group is in, so no need to call AddItems again. </syntaxhighlight> ==== OpRadioButton ==== This is an UIelement and it alone does not do anything. Its size is fixed to 24x24. {|class="wikitable" ! Constructor Parameter ! Default constructor |- | pos | BottomLeft position relative from the canvas origin. |} {|class="wikitable" !width="50%"| Constructor Parameter !width="50%"| Lazier version that accepts two float for pos |- | posX | Relative distance from the canvas origin to the left side of the UIelement. |- | posY | Relative distance from the canvas origin to bottom side of the UIelement. |} It has properties that’s the same name as UIconfigs, and they do identical things. {|class="wikitable" !width="50%"| Property !width="50%"| |- | greyedOut | If true, locks interaction with this button. The users still can interact with other OpRadioButton in the group. |- | colorEdge | The colour of its boundary and its symbol. |- | colorFill | The colour that fills inside. |- | ''value'' | The value of this, although this doesn’t get saved. ''valueBool'' returns this in bool. |- | bumpBehav | BumpBehaviour instance that’s bound to this. |} === OpDragger === [[File:Dragger.png|thumb|none|alt=OpDragger Sample|OpDragger Sample]] Rain World Dragger is a small box with a number, which the users can adjust by holding the mouse and move vertically. It is useful for cramping adjustable int value in a tight space. This returns int value. Its size is fixed to 24x24. {|class="wikitable" ! Constructor Parameter ! Default constructor |- | pos | BottomLeft position relative from the canvas origin. |- | key | Unique key to save and access the value. |- | ''defaultInt'' | Default value. |} {|class="wikitable" !width="50%"| Constructor Parameter !width="50%"| Lazier version that accepts two float for pos |- | posX | Relative distance from the canvas origin to the left side of the UIelement. |- | posY | Relative distance from the canvas origin to bottom side of the UIelement. |- | key | Unique key to save and access the value. |- | ''defaultInt'' | Default value. |} {|class="wikitable" ! Property ! |- | min | The minimum number this dragger is allowed to go. (default: 0) |- | max | The maximum number this dragger is allowed to go. (default: 99) |- | colorEdge | The colour of its boundary. |- | colorFill | The colour that fills inside. |- | colorText | The colour of its number inside. |} === OpSlider === [[File:Slider.png|thumb|none|alt=OpSlider Sample|OpSlider Sample]] [https://en.wikipedia.org/wiki/Slider_(computing) Slider] (a.k.a. TrackBar) allows the users to set value by dragging the indicator. Clicking a point on the slider also works. This returns int value. The width perpendicular to its length is fixed to 30. {|class="wikitable" ! Constructor Parameter ! Default constructor. |- | pos | BottomLeft position relative from the canvas origin. |- | key | Unique key to save and access the value. |- | range | Inclusive range of value. |- | length | The length of this element. |- | ''vertical'' | |- | ''defaultValue'' | Default value. |} {|class="wikitable" ! Constructor Parameter ! Length = range * multi |- | pos | BottomLeft position relative from the canvas origin. |- | key | Unique key to save and access the value. |- | range | |- | ''multi'' | How much pixels length each tick would take. |- | ''vertical'' | |- | ''defaultValue'' | Default value. |} ==== OpSliderSubtle ==== [[File:SliderSubtle.png|thumb|none|alt=OpSliderSubtle Sample|OpSliderSubtle Sample]] === OpKeyBinder === === OpComboBox === [[File:ComboBox.png|thumb|none|alt=OpComboBox Sample|OpComboBox Sample]] [https://en.wikipedia.org/wiki/Combo_box ComboBox] is a combination of [https://en.wikipedia.org/wiki/Drop-down_list Drop-down List] and SearchBox. ==== OpResourceSelector ==== ==== ListItem ==== While this technically belongs to [[##Custom-Classes|Custom Classes]], this is currently only used in <code>OpComboBox</code> so it will be included here. === OpColorPicker === [[File:ColorPicker.png|thumb|none|alt=OpColorPicker Sample|OpColorPicker Sample]] [https://en.wikipedia.org/wiki/Color_picker ColorPicker] (a.k.a. ColorChooser) allows the users to select a Color. OpColorPicker has four modes of selecting Color: RGB(Red/Green/Blue), HSL(Hue/Satuation/Lightness), PLT(Palette), and HEX (which can be copied and pasted from Clipboard). OpColorPicker stores value in HEX, so <code>OpColorPicker.HexToColor</code> method comes handy converting that. === OpTextBox === [https://en.wikipedia.org/wiki/Text_box TextBox] (a.k.a. TextField or TextEntryBox) allows the users to input text information. == UItrigger == === OpSimpleButton === SimpleButton is a [https://en.wikipedia.org/wiki/Button_(computing) PushButton] that allows the users to trigger an event. ==== OpSimpleImageButton ==== === OpHoldButton === [[File:HoldButton.png|thumb|none|alt=OpHoldButton Sample|OpHoldButton Sample]] == Custom Classes == === DyeableRect === === BumpBehaviour === === FTexture === === FCursor === === LabelTest === === LoremIpsum === {|class="wikitable" !width="50%"| Properties !width="50%"| |- | *_init* | Whether this is initialized in ConfigMenu or not. The same as <code>OptionInterface.isOptionMenu</code>. |- | ''menu'' | Rain World Menu instance this element is belong to. |- | ''owner'' | Rain World Page instance this element is belong to. |- | ''tab'' | OpTab instance this element is in. |- | ''subObjects'' | <code>MenuObject</code> instances this element has. |- | ''myContainer'' | FContainer that this element has. It gets initialized in constructor ''only'' when <code>_init</code>. |- | ''isHidden'' | Whether this is hidden and not visible. |- | ''fixedSize'' | If this is not null, this element’s size will always be this. (''fixedRad'' does the similar) |- | *_soundFill* | Add number (in proportion with sound effect’s length) to this whenever you’re playing soundeffect. |- | *_soundFilled* | If this is true, avoid excuting <code>menu.PlaySound</code> |} 64a0877b11a6e7712386632721d005390049b96b 190 187 2022-08-10T22:21:26Z Thalber 3 add todos wikitext text/x-wiki {{Cleanup}} This page is '''unfinished''' and needs to be expanded. This page contains a list of UIElements provided by default with [[ConfigMachine]]. Up to date with Config Machine <code>v1.5.1</code>. This page explains what each provided <code>UIelement</code> is and how to use them. You can check out the source code of Config Machine from its [https://github.com/metnias/CompletelyOptional github page], or have <code>ConfigMachine.xml</code> in your Reference folder for summaries. However, there are functions left unused (mainly because the modders are unaware) so this page will cover them. Some provided <code>UIelement</code>s have <code>fixedSize</code>, which prevents it being resized. The list of those follows: {|class="wikitable" ! UIelement !align="right"| width !align="right"| height |- | OpCheckBox |align="right"| 24 |align="right"| 24 |- | OpRadioButton |align="right"| 24 |align="right"| 24 |- | OpDragger |align="right"| 24 |align="right"| 24 |- | OpSlider |align="right"| **30* |align="right"| |- | OpSliderSubtle |align="right"| **30* |align="right"| |- | OpComboBox |align="right"| |align="right"| 24 |- | OpColorPicker |align="right"| 150 |align="right"| 150 |- | OpTextBox |align="right"| |align="right"| 24 |- | OpHoldButton |align="right"| rad: |align="right"| ''55'' |} (* The width perpendicular to its length is fixed) == UIelement == UIelement is everything that can be added in <code>OpTab</code>, which is 600x600 canvas. Its sub-categories are [[##UIconfig|UIconfig]] and [[##UItrigger|UItrigger]]. UIelement can be either rectangular (pos and size) or circular (pos and rad), although the vast majority of provided UIelements are rectangular. (''Italic'' properties call <code>OnChange</code> when modified) {|class="wikitable" !width="50%"| Property !width="50%"| |- | ''pos(setter)'' | Sets bottom-left position ''relative'' to its canvas (<code>OpTab</code>/<code>OpScrollBox</code>). |- | ''size'' | The size of the element. (When this is rectangular) |- | ''rad'' | The radius of the element. (When this is circular) |- | description | Infotext that will be shown at the bottom of the screen when MouseOver is true. |- | MouseOver | Whether the mouse cursor is over this element. |} {|class="wikitable" !width="50%"| Method !width="50%"| |- | Hide() | Hides this UIelement, and prevent interaction. |- | Show() | Unhide this UIelement. |- | GetPos() | Returns bottom-left position ''relative'' to its canvas (<code>OpTab</code>/<code>OpScrollBox</code>). (pos(getter) returns ''absolute'' position) |- | Reset() | Reset this UIelement if it’s possible. |- | FrameMultiply(origFrameCount) | (static) When you have a frame counter in Update, use this to accommodate with Many More Fixes’ FPS unlock feature. |- | DTMultiply(deltaTime) | (static) Without MMF’s FPS meddling, this returns somewhere close to <code>1f</code>. Use this for ticking gradual changes. |} === OpLabel === [[File:Label.png|thumb|none|alt=OpLabel Sample|OpLabel Sample]] Simply displays text. (''Italic'' parameters are optional) {|class="wikitable" !width="50%"| Constructor Parameter !width="50%"| Displays text aligned to defined rectangular |- | pos | BottomLeft position relative from the canvas origin. |- | size | Width and height of the rectangle this UIelement occupies. |- | ''text'' | Text to be displayed. Setting it empty will generate Lorem Ipsum for testing. |- | ''alignment'' | Horizontal alignment, whether the text is aligned to left, center, right with the rectangle defined its size. |- | ''bigText'' | Whether to use the bigger font or not. |} {|class="wikitable" !width="50%"| Constructor Parameter !width="50%"| Displays text that goes right from the position |- | posX | Relative distance from the canvas origin to the left side of the UIelement. |- | posY | Relative distance from the canvas origin to bottom side of the UIelement. |- | ''text'' | Text to be displayed. Setting it empty will generate Lorem Ipsum for testing. |- | ''bigText'' | Whether to use the bigger font or not. |} {|class="wikitable" !width="50%"| Property !width="50%"| |- | ''text'' | Text to be displayed. |- | autoWrap | If true, when the text goes over its width, a linebreak will be inserted. |- | ''alignment'' | Horizontal alignment, whether the text is aligned to left, center, right with the rectangle defined its size. |- | ''verticalAlignment'' | Vertical alignment, whether the text is aligned to top, center, bottom with the rectangle defined its size. |- | bumpBehav | <code>null</code> by default. Setting this to other bumpBehaviour will synchronize highlighting. Creating new BumpBehaviour with this label turns itself reactive. |- | color | Colour of the text. |} ==== OpLabelLong ==== A child class of [[###OpLabel|<code>OpLabel</code>]] that is specialized for displaying a long wall of text. This will always use the smaller font. {|class="wikitable" !width="50%"| Constructor Parameter !width="50%"| |- | pos | BottomLeft position relative from the canvas origin. |- | size | Width and height of the rectangle this UIelement occupies. |- | ''text'' | Text to be displayed. Setting it empty will generate Lorem Ipsum for testing. |- | autoWrap | If true, when the text goes over its width, a linebreak will be inserted. |- | ''alignment'' | Horizontal alignment, whether the text is aligned to left, center, right with the rectangle defined its size. |} {|class="wikitable" !width="50%"| Property !width="50%"| |- | allowOverflow | If it’s false, text that goes over the height will be discarded. |} === OpRect === [[File:Rect.png|thumb|none|alt=OpRect Sample|OpRect Sample]] Simple rectangular, useful to make a boundary to group UIelements. Z-order is the order they’re initialized, so for that purpose, initialize OpRect beforehand. {|class="wikitable" ! Constructor Parameter ! |- | pos | BottomLeft position relative from the canvas origin. |- | size | Width and height of the rectangle this UIelement occupies. |- | ''alpha'' | Alpha of the background of the rectangle. |} {|class="wikitable" !width="50%"| Property !width="50%"| |- | colorEdge | The colour of boundary sprites. |- | colorFill | The colour of fill sprites. |- | alpha | Alpha of the background of the rectangle. If doesBump, this gets ignored. |- | doesBump | If true, this rectangle reacts to mouse cursor hovering . |- | bumpBehav | If doesBump, this controls reaction. If not, this stays <code>null</code>. |} === OpImage === [[File:Image.png|thumb|none|alt=OpImage Sample|OpImage Sample]] Displays an image, whether it’s <code>FAtlasElement</code> that’s already loaded in <code>Futile.atlasManager</code>, or <code>Texture2D</code>. {|class="wikitable" ! Constructor Parameter ! Displays Texture2D |- | pos | BottomLeft position relative from the canvas origin. |- | image | Texture2D image to be displayed. |} {|class="wikitable" ! Constructor Parameter ! Displays FAtlasElement |- | pos | BottomLeft position relative from the canvas origin. |- | fAtlasElement | The name of FAtlasElement. |} {|class="wikitable" !width="50%"| Property !width="50%"| |- | ''color'' | The colour of the sprite. |- | ''anchor'' | The anchor of the sprite. (0f, 0f) to set pos as BottomLeft, and (0.5f, 0.5f) to set pos as the centre. |- | ''scale'' | The scale of the sprite. |- | ''alpha'' | The alpha of the sprite. |} You can change the image without making new OpImage. However, you cannot change the Texture2D version to FAtlasElement and vice versa. {|class="wikitable" ! Method ! |- | ChangeImage(newImage) | Swap image to new Texture2D. |- | ChangeElement(newElement) | Swap FAtlasElement to new one. |} === OpScrollBox === OpScrollBox is written by Slime_Cubed. It’s a special UIelement that acts as a canvas, like OpTab. [[File:ScrollBox_Box.png|thumb|none|alt=OpScrollBox Sample - Box|OpScrollBox Sample - Box]] {|class="wikitable" ! Constructor Parameter ! Rectangular ScrollBox inside OpTab |- | pos | BottomLeft position relative from the canvas origin. |- | size | The size of the display. |- | contentSize | Internal length of the scroll direction. |- | ''horizontal'' | Whether this scrolls horizontally or vertically. |- | ''hasBack'' | Whether its boundary will have filled backdrop or not. |- | ''hasSlideBar'' | Whether this will have a scrollbar or not. |} [[File:ScrollBox_Tab.png|thumb|none|alt=OpScrollBox Sample - Tab|OpScrollBox Sample - Tab]] {|class="wikitable" ! Constructor Parameter ! ScrollBox that replaces OpTab |- | tab | BottomLeft position relative from the canvas origin. |- | contentSize | The size of the display. |- | ''horizontal'' | Whether this scrolls horizontally or vertically. |- | ''hasSlideBar'' | Whether this will have a scrollbar or not. |} Think of OpScrollBox as a window that displays a larger canvas inside. The size of this window is the same as <code>size</code>. The size of the canvas inside has <code>contentSize</code> for its scroll-direction length, and the other length matches the width of this window. [[File:ScrollBox_Diagram.png|thumb|none|alt=OpScrollBox Diagram|OpScrollBox Diagram]] The diagram above would be coded like the following. Their <code>pos</code> is relative to the bottom left origin of the canvas inside the OpScrollBox. The result of this code is shown above. <syntaxhighlight lang="c#"> OpScrollBox scb = new OpScrollBox(new Vector2(100f, 100f), new Vector2(240f, 150f), 400f); Tabs[0].AddItems(scb); // Not required if you're using Tab version of constructor scb.AddItems(new OpLabelLong(new Vector2(20f, 20f), new Vector2(120f, 200f)), new OpSlider(new Vector2(160f, 30f), "_", new IntVector2(-20, 20), length: 180, true, 10)); // Use AddItems on OpScrollBox instead of OpTab </syntaxhighlight> {|class="wikitable" !width="50%"| Property !width="50%"| |- | redrawFlags | When this ScrollBox should be redrawn. Never / Always(default) / OnHover / OnKeypress. |- | colorEdge | Edge colour of rectangles. |- | colorFill | Fill colour of rectangles. |- | fillAlpha | Fill alpha of boundary rectangle. |- | doesBackBump | If false, the boundary rectangle does not react with mouseover. |- | ScrollLocked | Whether the scrolling is locked. Manipulated by <code>Lock</code> and <code>Unlock</code> method. |- | ScrollOffset | The visual offset, in pixels, of the contents of this ScrollBox. (&lt;=0) |- | MaxScroll | The value of <code>ScrollOffset</code> at the topmost or rightmost position of the box. (&lt;=0) |- | targetScrollOffset | The target value of <code>ScrollOffset</code>. Change this to smoothly animate scrolling. |} {|class="wikitable" !width="50%"| Method !width="50%"| |- | AddItems(items) | Adds a collection of items to the interior of this ScrollBox. Use this instead of <code>OpTab.AddItems</code> for its children. |- | Lock(stopImmediately) | Locks scrolling. If <code>stopImmediately</code>, ignore <code>targetScrollOffset</code> and stops immediately. |- | UnLock() | Unlocks scrolling. |- | ScrollToTop(''immediate'') | Scrolls to the top/leftmost. If <code>immediate</code>, scrolling animation gets cancelled. |- | ScrollToBottom(''immediate'') | Scrolls to the bottom/rightmost. If <code>immediate</code>, scrolling animation gets cancelled. |- | MarkDirty() | Forces redrawing at the end of this frame. |- | MarkDirty(time) | Forces redrawing for the amount of <code>time</code> in seconds. |} === OpContainer === This is an easy-to-access FContainer for ConfigMenu. {|class="wikitable" ! Constructor Parameter ! |- | pos | The origin of this element relative to the canvas origin. |} {|class="wikitable" !width="50%"| Property !width="50%"| |- | container | Accessible FContainer. You can access this without checking isOptionMenu. (NullRef-proof) |} == UIconfig == <code>UIconfig</code> is a subcategory of [[##UIelement|UIelement]], and has few extra properties and methods. Their value gets saved in <code>ModConfigs</code> folder in json format. If the key is either <code>null</code>, Empty, or starts with <code>_</code>, it is considered <code>cosmetic</code> and its value won’t be saved. For collecting config values, access <code>config</code> dictionary with <code>key</code> you’ve set, in <code>ConfigOnChange</code>. {|class="wikitable" !width="50%"| Property !width="50%"| |- | key | (readonly) Unique key to save and access the value. |- | ''value'' | The value that gets saved. <code>valueInt</code>, <code>valueFloat</code>, and <code>valueBool</code> exist which is useful for designing reactive GUI. |- | greyedOut | If true, the element gets greyed out visually and cannot be interacted with. |- | bumpBehav | <code>BumpBehaviour</code> instance this UIconfig has. |} {|class="wikitable" ! Method ! |- | ForceValue(newValue) | Change <code>value</code> without invoking <code>OnChange()</code>. |} === OpCheckBox === [[File:CheckBox.png|thumb|none|alt=OpCheckBox Sample|OpCheckBox Sample]] [https://en.wikipedia.org/wiki/Checkbox CheckBox] (a.k.a. TickBox) permits the user to make a binary choice. This returns bool (<code>&quot;true&quot;</code> or <code>&quot;false&quot;</code>). Its size is fixed to 24x24. {|class="wikitable" ! Constructor Parameter ! Default constructor |- | pos | BottomLeft position relative from the canvas origin. |- | key | Unique key to save and access the value. |- | ''defaultBool'' | Default value. |} {|class="wikitable" !width="50%"| Constructor Parameter !width="50%"| Lazier version that accepts two float for pos |- | posX | Relative distance from the canvas origin to the left side of the UIelement. |- | posY | Relative distance from the canvas origin to bottom side of the UIelement. |- | key | Unique key to save and access the value. |- | defaultBool | Default value. |} {|class="wikitable" ! Property ! |- | colorEdge | The colour of its boundary and its symbol. |- | colorFill | The colour that fills inside. |} === OpRadioButtonGroup === [[File:RadioButton.png|thumb|none|alt=OpRadioButton Sample|OpRadioButton Sample]] [https://en.wikipedia.org/wiki/Radio_button RadioButton] (a.k.a. OptionButton) permits the user to choose only one of a predefined set of mutually exclusive options. <code>OpRadioButton</code> is ''UIelement'' that ''looks'' like an UIconfig, but isn’t. <code>OpRadioButtonGroup</code>, albeit invisible, is what actually stores the value to be saved. This returns int value. As OpRadioButtonGroup is arbitary, it doesn’t need the <code>pos</code> to be initialized. However, if your OpRadioButtons should be in OpScrollBox, add OpRadioButtonGroup for its child instead of OpTab. {|class="wikitable" ! Constructor Parameter ! Default constructor |- | key | Unique key to save and access the value. |- | ''defaultValue'' | Default value. 0 or higher. |} {|class="wikitable" !width="50%"| Method !width="50%"| |- | buttons | OpRadioButtons that belong to this. Use SetButtons(buttons) to set. |} {|class="wikitable" !width="50%"| Method !width="50%"| |- | SetButtons(buttons) | Binds OpRadioButton to this. This also adds <code>OpRadioButton</code>s to the canvas this is in. |- | Hide() | Calls Hide() for all children. |- | Show() | Calls Show() for all children. |- | SetColorEdge(newColor) | Changes colorEdge of all children. |- | SetColorFill(newColor) | Changes colorFill of all children. |} Example: <syntaxhighlight lang="c#"> OpRadioButtonGroup group = new OpRadioButtonGroup("MyOption"); Tabs[1].AddItems(group); // Add this to canvas before calling SetButtons group.SetButtons(new OpRadioButton[] { new OpRadioButton(300f, 450f), new OpRadioButton(350f, 450f) }); // SetButtons adds params to the canvas the group is in, so no need to call AddItems again. </syntaxhighlight> ==== OpRadioButton ==== This is an UIelement and it alone does not do anything. Its size is fixed to 24x24. {|class="wikitable" ! Constructor Parameter ! Default constructor |- | pos | BottomLeft position relative from the canvas origin. |} {|class="wikitable" !width="50%"| Constructor Parameter !width="50%"| Lazier version that accepts two float for pos |- | posX | Relative distance from the canvas origin to the left side of the UIelement. |- | posY | Relative distance from the canvas origin to bottom side of the UIelement. |} It has properties that’s the same name as UIconfigs, and they do identical things. {|class="wikitable" !width="50%"| Property !width="50%"| |- | greyedOut | If true, locks interaction with this button. The users still can interact with other OpRadioButton in the group. |- | colorEdge | The colour of its boundary and its symbol. |- | colorFill | The colour that fills inside. |- | ''value'' | The value of this, although this doesn’t get saved. ''valueBool'' returns this in bool. |- | bumpBehav | BumpBehaviour instance that’s bound to this. |} === OpDragger === [[File:Dragger.png|thumb|none|alt=OpDragger Sample|OpDragger Sample]] Rain World Dragger is a small box with a number, which the users can adjust by holding the mouse and move vertically. It is useful for cramping adjustable int value in a tight space. This returns int value. Its size is fixed to 24x24. {|class="wikitable" ! Constructor Parameter ! Default constructor |- | pos | BottomLeft position relative from the canvas origin. |- | key | Unique key to save and access the value. |- | ''defaultInt'' | Default value. |} {|class="wikitable" !width="50%"| Constructor Parameter !width="50%"| Lazier version that accepts two float for pos |- | posX | Relative distance from the canvas origin to the left side of the UIelement. |- | posY | Relative distance from the canvas origin to bottom side of the UIelement. |- | key | Unique key to save and access the value. |- | ''defaultInt'' | Default value. |} {|class="wikitable" ! Property ! |- | min | The minimum number this dragger is allowed to go. (default: 0) |- | max | The maximum number this dragger is allowed to go. (default: 99) |- | colorEdge | The colour of its boundary. |- | colorFill | The colour that fills inside. |- | colorText | The colour of its number inside. |} === OpSlider === [[File:Slider.png|thumb|none|alt=OpSlider Sample|OpSlider Sample]] [https://en.wikipedia.org/wiki/Slider_(computing) Slider] (a.k.a. TrackBar) allows the users to set value by dragging the indicator. Clicking a point on the slider also works. This returns int value. The width perpendicular to its length is fixed to 30. {|class="wikitable" ! Constructor Parameter ! Default constructor. |- | pos | BottomLeft position relative from the canvas origin. |- | key | Unique key to save and access the value. |- | range | Inclusive range of value. |- | length | The length of this element. |- | ''vertical'' | |- | ''defaultValue'' | Default value. |} {|class="wikitable" ! Constructor Parameter ! Length = range * multi |- | pos | BottomLeft position relative from the canvas origin. |- | key | Unique key to save and access the value. |- | range | |- | ''multi'' | How much pixels length each tick would take. |- | ''vertical'' | |- | ''defaultValue'' | Default value. |} ==== OpSliderSubtle ==== [[File:SliderSubtle.png|thumb|none|alt=OpSliderSubtle Sample|OpSliderSubtle Sample]] === OpKeyBinder === {{todo}} === OpComboBox === [[File:ComboBox.png|thumb|none|alt=OpComboBox Sample|OpComboBox Sample]] [https://en.wikipedia.org/wiki/Combo_box ComboBox] is a combination of [https://en.wikipedia.org/wiki/Drop-down_list Drop-down List] and SearchBox. ==== OpResourceSelector ==== {{todo}} ==== ListItem ==== While this technically belongs to [[##Custom-Classes|Custom Classes]], this is currently only used in <code>OpComboBox</code> so it will be included here. === OpColorPicker === [[File:ColorPicker.png|thumb|none|alt=OpColorPicker Sample|OpColorPicker Sample]] [https://en.wikipedia.org/wiki/Color_picker ColorPicker] (a.k.a. ColorChooser) allows the users to select a Color. OpColorPicker has four modes of selecting Color: RGB(Red/Green/Blue), HSL(Hue/Satuation/Lightness), PLT(Palette), and HEX (which can be copied and pasted from Clipboard). OpColorPicker stores value in HEX, so <code>OpColorPicker.HexToColor</code> method comes handy converting that. === OpTextBox === [https://en.wikipedia.org/wiki/Text_box TextBox] (a.k.a. TextField or TextEntryBox) allows the users to input text information. == UItrigger == {{todo}} === OpSimpleButton === SimpleButton is a [https://en.wikipedia.org/wiki/Button_(computing) PushButton] that allows the users to trigger an event. ==== OpSimpleImageButton ==== {{todo}} === OpHoldButton === {{todo}} [[File:HoldButton.png|thumb|none|alt=OpHoldButton Sample|OpHoldButton Sample]] == Custom Classes == {{todo}} === DyeableRect === {{todo}} === BumpBehaviour === {{todo}} === FTexture === {{todo}} === FCursor === {{todo}} === LabelTest === {{todo}} === LoremIpsum === {|class="wikitable" !width="50%"| Properties !width="50%"| |- | *_init* | Whether this is initialized in ConfigMenu or not. The same as <code>OptionInterface.isOptionMenu</code>. |- | ''menu'' | Rain World Menu instance this element is belong to. |- | ''owner'' | Rain World Page instance this element is belong to. |- | ''tab'' | OpTab instance this element is in. |- | ''subObjects'' | <code>MenuObject</code> instances this element has. |- | ''myContainer'' | FContainer that this element has. It gets initialized in constructor ''only'' when <code>_init</code>. |- | ''isHidden'' | Whether this is hidden and not visible. |- | ''fixedSize'' | If this is not null, this element’s size will always be this. (''fixedRad'' does the similar) |- | *_soundFill* | Add number (in proportion with sound effect’s length) to this whenever you’re playing soundeffect. |- | *_soundFilled* | If this is true, avoid excuting <code>menu.PlaySound</code> |} d3d746f036bd310729d86dff5b53f6dcb1cc4a5b Legacy Mod Installation 0 119 188 2022-08-10T22:05:29Z Thalber 3 Make Installation guide stub wikitext text/x-wiki {{Cleanup}} This page contains instructions on how to install and use available mods. Most mods and tools are available on [raindb.net] or in <nowiki>#modding-releases</nowiki> channel of [discord.gg/rainworld RW Discord server]. == Basics == === BOI + Bepinex === # Download latest BOI release [https://github.com/Rain-World-Modding/BOI/releases/latest here]. # Unpack anywhere on your pc. Preferrably not into the game folder. Make sure all files from the zip are in the same directory. # Run <code>BOI.exe</code>. # Press "Select game folder". # Navigate to game dir and select RainWorld's .exe, "press again to load modlist". # Open "Download mods / install BepInEx". # In the subwindow, press "Install Bepinex". Wait 15 to 20 seconds until the window unfreezes. Mod <code>.dll</code> files go into <code>Rain World/Mods/</code>. You can also drag and drop them into BOI modlist. Use Tags field to set notes for your mods, you can use the search box to filter mods later. When uninstalling mods, disable them in BOI first. Things to note: * Older versions of BOI use a different dialog window for path selection, that one requires you to select the folder game exe is in, not the exe itself. === Bepinex === This is mostly useful if you're not on Windows and don't want to bother emulating an extra app. # Download latest package [https://beestuff.pythonanywhere.com/audb/api/v2/bepinex/download here] # Without changing folder structure, unpack into the game folder so that the folder structure looks like the following: <!--[[File:BepInEx-FolderStructure/png|none|thumb|alt=Correct folder structure|Correct folder structure]]--> <syntaxhighlight> Rain World/ L__ BepInEx/ L__ core/ L__ patchers/ L__ monomod/ L__ plugins/ L___ ... all normal game directories ... L___ RainWorld.exe L___ doorstop_config.ini L___ winhttp.dll </syntaxhighlight> [[BepInPlugins]] and [[Partiality|partmods]] go into <code>Rain World/BepInEx/plugins/</code>. [[MonoMod patches]] go into <code>Rain World/BepInEx/monomod/</code> (they need to be renamed to template <code>AssemblyCSharp.[modname].mm.dll</code>). [[Preloader patchers]] go into <code>Rain World/BepInEx/patchers/</code>. == Region packs == For this, you'll need to have completed [[#Basics]]. To install custom regions, you will first need [[CRS]] and all of its dependencies. === In-game installer === From CRS Config menu, you can easily install most publicly released region mods in one click from "browse RainDB" tab. You may need to relaunch the game to reload dependency DLLs after everything is done downloading. === Manual instalation === This is useful for installing regpacks that are not publicly available. # Download the regpack archive # Without changing folder structure, unpack it into <code>Rain World/Mods/CustomResources/</code> so that the resulting folders look like the following: <syntaxhighlight> Rain World/ L__ Mods/ L__ CustomResources/ L__ YourRegionMod/ L___ Assets/ L___ World/ L___ Levels/ L___ packInfo.json L___ thumb.png </syntaxhighlight> == Standalone mods == {{todo}} == Sprite packs == {{todo}} [[Category:End user guides]] 65363a57f4c1953989b40f4a1b0dcd70ef039378 200 188 2022-08-11T03:29:20Z Thalber 3 wikitext text/x-wiki {{Cleanup}} This page contains instructions on how to install and use available mods, as well as modloaders. Most mods and tools are available on [raindb.net] or in <nowiki>#modding-releases</nowiki> channel of [discord.gg/rainworld RW Discord server]. When installing a mod, refer to its README file if there is one. You can see what type a mod is by hovering a square icon next to its name on RainDB. == Installing the modloader == === BOI + Bepinex === # Download latest BOI release [https://github.com/Rain-World-Modding/BOI/releases/latest here]. # Unpack anywhere on your PC. Preferrably not into the game folder. Make sure all files from the zip are in the same directory. # Run <code>BOI.exe</code>. # Press "Select game folder". # Navigate to game dir and select RainWorld's .exe, "press again to load modlist". # Open "Download mods / install BepInEx". # In the subwindow, press "Install Bepinex". Wait 15 to 20 seconds until the window unfreezes. Things to note: * Older versions of BOI use a different dialog window for path selection, that one requires you to select the folder game exe is in, not the exe itself. === Bepinex === This is mostly useful if you're not on Windows and don't want to bother emulating an extra app. # Download latest package [https://beestuff.pythonanywhere.com/audb/api/v2/bepinex/download here] # Without changing folder structure, unpack into the game folder so that the folder structure looks like the following: <!--[[File:BepInEx-FolderStructure/png|none|thumb|alt=Correct folder structure|Correct folder structure]]--> <syntaxhighlight> Rain World/ L__ BepInEx/ L__ core/ L__ patchers/ L__monomod/ L__plugins/ L__ ... all normal game directories ... L__ RainWorld.exe L__ doorstop_config.ini L__ winhttp.dll </syntaxhighlight> == Installing code mods == === BepInEx + BOI === Mod <code>.dll</code> files go into <code>Rain World/Mods/</code>. You can also drag and drop them into BOI modlist. Use Tags field to set notes for your mods, you can use the search box to filter mods later. Toggle in BOI to enable/disable. To uninstall, uncheck then delete from <code>/Mods/</code>. === Raw BepInEx === [[BepInPlugins]] and [[Partiality|partmods]] go into <code>Rain World/BepInEx/plugins/</code>. [[MonoMod Patches]] go into <code>Rain World/BepInEx/monomod/</code> (they need to be renamed to template <code>AssemblyCSharp.[modname].mm.dll</code>). [[Preloader Patchers]] go into <code>Rain World/BepInEx/patchers/</code>. To uninstall, delete mod .dll file from respective active folder. == Installing region packs == For this, you'll need to have completed [[#Installing the modloader]]. To install custom regions, you will first need [[CRS]] and all of its dependencies. === In-game installer === From CRS Config menu, you can easily install most publicly released region mods in one click from "browse RainDB" tab. You may need to relaunch the game to reload dependency DLLs after everything is done downloading. === Manual === This is useful for installing regpacks that are not publicly available. # Download the regpack archive # Without changing folder structure, unpack it into <code>Rain World/Mods/CustomResources/</code> so that the resulting folders look like the following: <syntaxhighlight> Rain World/ L__ Mods/ L__ CustomResources/ L__ YourRegionMod/ L___ Assets/ L___ World/ L___ Levels/ L___ packInfo.json L___ thumb.png </syntaxhighlight> == Installing standalone mods == [[Standalone Mods]] are installed by folder merging. They usually come as an archive with a folder called <code>Rain World</code> in it. To install a standalone mod, unpack its archive and drag Rain World subfolder from it onto the main game folder, select "replace all files". To uninstall a standalone mod, go to Steam library, right click on Rain World, select Properties -> Local files -> Verify integrity of game files. If you are not on steam, you will probably need to wipe and reinstall your game. == Sprite packs == Sprite packs are asset bundles containing sprite replacements for slugcats. To use them, you need # An asset loader. It can be: #* [[Custom Sprites Loader]] aka CSL (Partmod, instances are additionally bundled with RegionKit) #* [[CustomAssets]] (MMPatch) # A character customizer mod. It can be: #* [[FancySlugcats]] (partmod) #* [[ShinyRat]] (Bepinex plugin) Sprite packs usually come with their own READMEs. * When using CustomAssets, the usual way to install a sprite pack is by folder merge. * When using CSL, the sprites can be put into <code>ModConfigs/CustomSpritesLoader/Load/</code> or any subfolder inside it (you need to run the game once with CSL enabled for the folder to be generated). After the sprites have been put into their place, run the game and head into your character customizer's config menu to set sprite names. * When using FancySlugcats, be sure to exactly input sprite names as shown in your sprite pack's README. If you input a name wrong, the game will freeze on start. FancySlugcats is terminally incompatible with some custom character mods. * ShinyRat is crash resistant and more or less works with most character mods. <!--[[Category:End user guides]]--> b5e8000da4aca892232bd34803cb60fdedadccb1 Template:todo 10 120 189 2022-08-10T22:17:59Z Thalber 3 Created page with "<includeonly><div class="nomobile">{{Ambox | image = <p><span style="margin-right:15px>[[File:Hardhatcat.png|33px|middle]]</span> | type = '''This {{{target|section}}} is unfinished''' | info = This {{{target|section}}} is lacking some / all of critical information.</p> | border = gray }}</div> [[Category:Unfinished]] </includeonly> <noinclude> Usage: <nowiki>{{todo|target=table}} (target defaults to "section")</nowiki> {{todo}} {{todo|target=table}} </noinclude>" wikitext text/x-wiki <includeonly><div class="nomobile">{{Ambox | image = <p><span style="margin-right:15px>[[File:Hardhatcat.png|33px|middle]]</span> | type = '''This {{{target|section}}} is unfinished''' | info = This {{{target|section}}} is lacking some / all of critical information.</p> | border = gray }}</div> [[Category:Unfinished]] </includeonly> <noinclude> Usage: <nowiki>{{todo|target=table}} (target defaults to "section")</nowiki> {{todo}} {{todo|target=table}} </noinclude> a4199d8a3abafba04fe30de45106fcf72c07d158 Category:Unfinished 14 121 191 2022-08-10T22:22:30Z Thalber 3 Created page with "This category contains pages that are missing some / all of the required information." wikitext text/x-wiki This category contains pages that are missing some / all of the required information. 0960f2b030be96322283805596a4b1ae032e3650 Dev Tools 0 84 192 122 2022-08-11T00:15:36Z Thalber 3 Fixed tabber names and some formatting wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ==Interface Tabs== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. <tabber> |-| Room settings= This tab mostly contains settings for base room visuals, such as palette, cloud cover and terrain wetness. === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === [[File:Fadepalette example.png]] ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image on the right shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! {|class="wikitable" |- ! '''Effect''' !! '''Description''' |- | SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. |- | SkyBloom || Increases how fuzzy/bloomy the sky's light is. |- | LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. |- | Bloom || Similar to SkyBloom, but applies to lights. |- | Fog || Creates a white cloudy effect at layer 1. Not compatible with |- | Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- |- | GreenSparks || Underhang, and the Legs' green sparkles. |- | VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | Flies || Spawns small flys that buzz around the room and land on objects. |- | FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | TinyDragonFly || Spawns tiny bugs that fly around plants. |- | RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | Ant || Spawns small jumping bugs. |- | Beetle || Spawns small beetles that slowly fly around the room. |- | WaterGlowWorm || Spawns small worms that swim around in water. |- | Wasp || Spawns small wasps that quickly dart between walls. |- | Moth || Spawns small white moths which slowly flutter around the room. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom`, VoidMelt </syntaxhighlight> |-| Objects= Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds= [[File:soundTab.png|400px|right|border|]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map= {{todo|target=tab}} [[File:mapTab.png|400px|right|border|]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections.png|400px|right|border|Connections on dev map]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png|400px|right|border|Canon view of the map]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png|400px|right|border|Example of a rendered map .png file]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers= {{todo|target=tab}} [[File:triggerTab.png|600px|right|border|Trigger tab view]] <span id="general-controls"></span> == General controls == === Save === Saves the current effects and room settings to a file inside the region’s World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by pressing R and returning to the room to see the changes. === Inherent from template === Will set the values stored in a specific template the region has to this room. === Save as template: === Saves the current room’s settings as a template for easy re-use. == Triggers Menu == '''Triggers''' are the mechanism in which some in-game events occur, such as specific songs playing, projections being displayed by the player guide overseer, or information text being displayed at the bottom of the screen. Clicking one of the four options in the bottom right-hand box will place a trigger of that type, which can be moved just like other devtools objects. === Trigger Options === Triggers have a number of settings which determine what the trigger does and under what circumstances. {| class="wikitable" |+ |- ! Trigger setting !! Description |- | Active from cycle || The minimum total cycle requirement for the trigger to activate. |- | Active up to cycle || The maximum cycle limit for the trigger to activate - if the player has a cycle count higher than this number, the trigger will not activate. |- | Fire chance || A random percentage chance for the trigger to activate, from 0% to 100%. |- | Trigger delay || How many seconds between the requirements for the trigger being met and the event occurring. |- | Karma req || The minimum karma the player needs for the trigger to activate (from 0 to 5) |- | Can only fire once/Can fire multiple times || Self-explanatory, determines whether the trigger only fires once or not. |- | No entrance requirement/Entrance XX || Determines whether the player can enter from any entrance pipe, or whether they need to come through a specific one. When an entrance is selected, a red line will connect this entrance and the options box. |- | White, Yellow, Red || Determines which gamemodes the trigger fires on - Survivor, Hunter or Monk. A gamemode’s name being displayed means that the trigger will fire in said gamemode. |} === Event Types === The lowest button on the options box lets you pick what type of event you want to add. ==== MusicEvent ==== Plays a song from the soundtrack. * The first button lets you pick the song you want to play. Files for these songs can be found in *Rain World, or many of them can be found [https://www.youtube.com/playlist?list=PLPJWSVeszYFBo1oAXYgzGfJfewnGKgGna online.] {| class="wikitable" |+ MusicEvent options |- ! Option !! Description |- | Play volume || The volume the song plays at. |- | Fade in || In seconds, how long the song takes to reach full volume. |- | Song priority || If this song’s priority is higher than another’s, then this song will continue to play if the other trigger is activated. If the priority is lower, then the higher one will play instead of it. |- | Drone volume || WIP, presumably adds a background drone sound at the set volume. |- | Fade out at threat || The threat level at which the song fades out and is overtaken by the threat music. |- | Rest cycles || If this trigger can activate multiple times, the number of cycles for the trigger to wait before being able to fire again. |- | Room transitions || How many rooms the song will continue playing through. |- | One song per cycle || Whether or not the same song can activate multiple times in one cycle. |- | Play once/loop || Determines whether the song plays once or loops |- | Continue at death || Continue playing the song when the player dies. |- | Continue through gate || Continue playing the song when the player uses a region gate. |} ==== StopMusicEvent ==== As the name says, stops one or more MusicEvents. The first button lets you pick the song you want to stop/exclude. * '''Priority:''' If a song has a higher priority than the trigger, it won’t stop. * '''Fade out:''' Same as fade in, but fading out to silence. * '''Stop all songs/stop specific song/stop all but specific song:''' Self-explanatory, song selected at the top of the box is what this refers to. ==== '''PoleMimicSubtleReveal''' ==== Causes a pole mimic to flutter slightly when activated. ==== '''ShowProjectedImageEvent''' ==== Shows player guide overseer projections ==== '''RoomSpecificTextMessage''' ==== Causes specific text prompt to appear. Prompts are hardcoded by room name {{Cn}} ==== '''BringPlayerGuideToRoom''' ==== Forces player overseer to current room === Trigger Types === * '''Spot:''' The most commonly used trigger; activates when slugcat walks into a specific circular area of the room. This is indicated by a white area-of-effect which can be moved and scaled. * '''SeeCreature:''' ''WIP, presumably activates upon a certain creature being seen.'' * '''RegionBump:''' Activates either when the region is entered or at the beginning of a cycle where the region name and cycle count is shown. * '''PreRegionBump:''' Seemingly functions the same way as RegionBump. </tabber> <div> [[Category:Devtools]] 00d32a0a8f196bd19eb919b983950c798530bc65 Rain World Modding:General disclaimer 4 122 193 2022-08-11T00:33:23Z Thalber 3 Copied from main wiki with minor alterations wikitext text/x-wiki {{SITENAME}} is an online, public collaboration of information centering around Rain World. All information contained on this website is provided by the voluntary efforts of the Rain World modding community. This website is an open wiki. Please note that articles and information found within this wiki has not necessarily been reviewed for truthfulness and/or relevancy. We cannot guarantee the validity and quality of the information. It should be understood that the content of any article may be modified or changed at any time by any member of the community. It should also be understood that any wiki page has a risk of becoming vandalized or improperly altered by others. It is encouraged that any user encountering improper, offensive, or otherwise incorrect information simply take the time to edit the article in question and correct the problem. If any situations arise that warrant further involvement, they should be reported directly to Rain World Wiki moderators for review. == Trademarks == Any of the trademarks, service marks, collective marks, design rights, personality rights, or similar rights that are mentioned, used, or cited in a Rain World Wiki article are the property of their respective owners. Unless otherwise stated, Rain World Wiki is neither endorsed nor affiliated with any of the holders of any such rights. [[Category:Legal notices]] a64652e01fc6b90f664789ce462fd8732c71f44a 195 193 2022-08-11T00:42:42Z Thalber 3 wikitext text/x-wiki {{SITENAME}} is an online, public collaboration of information centering around Rain World. All information contained on this website is provided by the voluntary efforts of the Rain World modding community. This website is an open wiki. Please note that articles and information found within this wiki has not necessarily been reviewed for truthfulness and/or relevancy. We cannot guarantee the validity and quality of the information. It should be understood that the content of any article may be modified or changed at any time by any member of the community. It should also be understood that any wiki page has a risk of becoming vandalized or improperly altered by others. It is encouraged that any user encountering improper, offensive, or otherwise incorrect information simply take the time to edit the article in question and correct the problem. If any situations arise that warrant further involvement, they should be reported directly to Rain World Wiki moderators for review. == Trademarks == Any of the trademarks, service marks, collective marks, design rights, personality rights, or similar rights that are mentioned, used, or cited in a Rain World Wiki article are the property of their respective owners. Unless otherwise stated, Rain World Wiki is neither endorsed nor affiliated with any of the holders of any such rights. c8ed25c3cdf9f592faa317a8ef49caa7bd894ef5 196 195 2022-08-11T00:46:03Z Thalber 3 wikitext text/x-wiki {{SITENAME}} is an online, public collaboration of information centering around modification of Rain World. All information contained on this website is provided by the voluntary efforts of the Rain World modding community. This website is an open wiki. Please note that articles and information found within this wiki has not necessarily been reviewed for truthfulness and/or relevancy. We cannot guarantee the validity and quality of the information. It should be understood that the content of any article may be modified or changed at any time by any member of the community. It should also be understood that any wiki page has a risk of becoming vandalized or improperly altered by others. It is encouraged that any user encountering improper, offensive, or otherwise incorrect information simply take the time to edit the article in question and correct the problem. If any situations arise that warrant further involvement, they should be reported directly to {{SITENAME}} moderators for review. == Trademarks == Any of the trademarks, service marks, collective marks, design rights, personality rights, or similar rights that are mentioned, used, or cited in a {{SITENAME}} article are the property of their respective owners. Unless otherwise stated, {{SITENAME}} is neither endorsed nor affiliated with any of the holders of any such rights. a331eebbadddb752429515f70eed97d782bb6f18 198 196 2022-08-11T00:47:56Z Thalber 3 Protected "[[Rain World Modding:General disclaimer]]": About/legal notice page ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite)) wikitext text/x-wiki {{SITENAME}} is an online, public collaboration of information centering around modification of Rain World. All information contained on this website is provided by the voluntary efforts of the Rain World modding community. This website is an open wiki. Please note that articles and information found within this wiki has not necessarily been reviewed for truthfulness and/or relevancy. We cannot guarantee the validity and quality of the information. It should be understood that the content of any article may be modified or changed at any time by any member of the community. It should also be understood that any wiki page has a risk of becoming vandalized or improperly altered by others. It is encouraged that any user encountering improper, offensive, or otherwise incorrect information simply take the time to edit the article in question and correct the problem. If any situations arise that warrant further involvement, they should be reported directly to {{SITENAME}} moderators for review. == Trademarks == Any of the trademarks, service marks, collective marks, design rights, personality rights, or similar rights that are mentioned, used, or cited in a {{SITENAME}} article are the property of their respective owners. Unless otherwise stated, {{SITENAME}} is neither endorsed nor affiliated with any of the holders of any such rights. a331eebbadddb752429515f70eed97d782bb6f18 Rain World Modding:About 4 123 194 2022-08-11T00:42:16Z Thalber 3 Create about page wikitext text/x-wiki {{SITENAME}} is an open web-based database of media, guides and technical reference related to modification of [https://rainworldgame.com/ Rain World]. It is created and maintained entirely by volunteering users. Our and yours activity here are under Miraheze's [https://meta.miraheze.org/wiki/Terms_of_Use Terms of Use]. [[Project:Copyrights|Copyright notices]] [[Project:General disclaimer|Content disclaimers]] a2189b6588e22dab3df1cca5c4121d95dcd6477c 197 194 2022-08-11T00:47:09Z Thalber 3 Protected "[[Rain World Modding:About]]": About/legal notice page ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite)) wikitext text/x-wiki {{SITENAME}} is an open web-based database of media, guides and technical reference related to modification of [https://rainworldgame.com/ Rain World]. It is created and maintained entirely by volunteering users. Our and yours activity here are under Miraheze's [https://meta.miraheze.org/wiki/Terms_of_Use Terms of Use]. [[Project:Copyrights|Copyright notices]] [[Project:General disclaimer|Content disclaimers]] a2189b6588e22dab3df1cca5c4121d95dcd6477c Talk:ConfigMachine 1 124 199 2022-08-11T02:56:21Z Thalber 3 Created page with "encoding corrupt somewhen back at GH, fix or replace lang ~~~~" wikitext text/x-wiki encoding corrupt somewhen back at GH, fix or replace lang [[User:Thalber|Thalber]] ([[User talk:Thalber|talk]]) 02:56, August 11, 2022 (UTC) e1b14e59b6ab15e94e8a804b42dc33f864ff710e Legacy Mod Installation 0 119 201 200 2022-08-11T03:41:41Z Thalber 3 /* Sprite packs */ wikitext text/x-wiki {{Cleanup}} This page contains instructions on how to install and use available mods, as well as modloaders. Most mods and tools are available on [raindb.net] or in <nowiki>#modding-releases</nowiki> channel of [discord.gg/rainworld RW Discord server]. When installing a mod, refer to its README file if there is one. You can see what type a mod is by hovering a square icon next to its name on RainDB. == Installing the modloader == === BOI + Bepinex === # Download latest BOI release [https://github.com/Rain-World-Modding/BOI/releases/latest here]. # Unpack anywhere on your PC. Preferrably not into the game folder. Make sure all files from the zip are in the same directory. # Run <code>BOI.exe</code>. # Press "Select game folder". # Navigate to game dir and select RainWorld's .exe, "press again to load modlist". # Open "Download mods / install BepInEx". # In the subwindow, press "Install Bepinex". Wait 15 to 20 seconds until the window unfreezes. Things to note: * Older versions of BOI use a different dialog window for path selection, that one requires you to select the folder game exe is in, not the exe itself. === Bepinex === This is mostly useful if you're not on Windows and don't want to bother emulating an extra app. # Download latest package [https://beestuff.pythonanywhere.com/audb/api/v2/bepinex/download here] # Without changing folder structure, unpack into the game folder so that the folder structure looks like the following: <!--[[File:BepInEx-FolderStructure/png|none|thumb|alt=Correct folder structure|Correct folder structure]]--> <syntaxhighlight> Rain World/ L__ BepInEx/ L__ core/ L__ patchers/ L__monomod/ L__plugins/ L__ ... all normal game directories ... L__ RainWorld.exe L__ doorstop_config.ini L__ winhttp.dll </syntaxhighlight> == Installing code mods == === BepInEx + BOI === Mod <code>.dll</code> files go into <code>Rain World/Mods/</code>. You can also drag and drop them into BOI modlist. Use Tags field to set notes for your mods, you can use the search box to filter mods later. Toggle in BOI to enable/disable. To uninstall, uncheck then delete from <code>/Mods/</code>. === Raw BepInEx === [[BepInPlugins]] and [[Partiality|partmods]] go into <code>Rain World/BepInEx/plugins/</code>. [[MonoMod Patches]] go into <code>Rain World/BepInEx/monomod/</code> (they need to be renamed to template <code>AssemblyCSharp.[modname].mm.dll</code>). [[Preloader Patchers]] go into <code>Rain World/BepInEx/patchers/</code>. To uninstall, delete mod .dll file from respective active folder. == Installing region packs == For this, you'll need to have completed [[#Installing the modloader]]. To install custom regions, you will first need [[CRS]] and all of its dependencies. === In-game installer === From CRS Config menu, you can easily install most publicly released region mods in one click from "browse RainDB" tab. You may need to relaunch the game to reload dependency DLLs after everything is done downloading. === Manual === This is useful for installing regpacks that are not publicly available. # Download the regpack archive # Without changing folder structure, unpack it into <code>Rain World/Mods/CustomResources/</code> so that the resulting folders look like the following: <syntaxhighlight> Rain World/ L__ Mods/ L__ CustomResources/ L__ YourRegionMod/ L___ Assets/ L___ World/ L___ Levels/ L___ packInfo.json L___ thumb.png </syntaxhighlight> == Installing standalone mods == [[Standalone Mods]] are installed by folder merging. They usually come as an archive with a folder called <code>Rain World</code> in it. To install a standalone mod, unpack its archive and drag Rain World subfolder from it onto the main game folder, select "replace all files". To uninstall a standalone mod, go to Steam library, right click on Rain World, select Properties -> Local files -> Verify integrity of game files. If you are not on steam, you will probably need to wipe and reinstall your game. == Sprite packs == Sprite packs are asset bundles containing sprite replacements for slugcats. To use them, you need # An asset loader. It can be: #* [[Custom Sprites Loader]] aka CSL (Partmod<!--, instances are additionally bundled with RegionKit-->) #* [[CustomAssets]] (MMPatch) # A character customizer mod. It can be: #* [[FancySlugcats]] (partmod) #* [[ShinyRat]] (Bepinex plugin) Sprite packs usually come with their own READMEs. * When using CustomAssets, the usual way to install a sprite pack is by folder merge. * When using CSL, the sprites can be put into <code>ModConfigs/CustomSpritesLoader/Load/</code> or any subfolder inside it (you need to run the game once with CSL enabled for the folder to be generated). After the sprites have been put into their place, run the game and head into your character customizer's config menu to set sprite names. * When using FancySlugcats, be sure to exactly input sprite names as shown in your sprite pack's README. If you input a name wrong, the game will freeze on start. FancySlugcats is terminally incompatible with some custom character mods. * ShinyRat is crash resistant and more or less works with most character mods. <!--[[Category:End user guides]]--> 23e88953cf09e182f0919b6f7fe2b0695c53952e 202 201 2022-08-12T10:35:24Z Cashewww 2 fixed url formatting wikitext text/x-wiki {{Cleanup}} This page contains instructions on how to install and use available mods, as well as modloaders. Most mods and tools are available on [https://raindb.net/ rainDB] or in <nowiki>#modding-releases</nowiki> channel of [https://discord.gg/rainworld RW Discord server]. When installing a mod, refer to its README file if there is one. You can see what type a mod is by hovering a square icon next to its name on RainDB. == Installing the modloader == === BOI + Bepinex === # Download latest BOI release [https://github.com/Rain-World-Modding/BOI/releases/latest here]. # Unpack anywhere on your PC. Preferrably not into the game folder. Make sure all files from the zip are in the same directory. # Run <code>BOI.exe</code>. # Press "Select game folder". # Navigate to game dir and select RainWorld's .exe, "press again to load modlist". # Open "Download mods / install BepInEx". # In the subwindow, press "Install Bepinex". Wait 15 to 20 seconds until the window unfreezes. Things to note: * Older versions of BOI use a different dialog window for path selection, that one requires you to select the folder game exe is in, not the exe itself. === Bepinex === This is mostly useful if you're not on Windows and don't want to bother emulating an extra app. # Download latest package [https://beestuff.pythonanywhere.com/audb/api/v2/bepinex/download here] # Without changing folder structure, unpack into the game folder so that the folder structure looks like the following: <!--[[File:BepInEx-FolderStructure/png|none|thumb|alt=Correct folder structure|Correct folder structure]]--> <syntaxhighlight> Rain World/ L__ BepInEx/ L__ core/ L__ patchers/ L__monomod/ L__plugins/ L__ ... all normal game directories ... L__ RainWorld.exe L__ doorstop_config.ini L__ winhttp.dll </syntaxhighlight> == Installing code mods == === BepInEx + BOI === Mod <code>.dll</code> files go into <code>Rain World/Mods/</code>. You can also drag and drop them into BOI modlist. Use Tags field to set notes for your mods, you can use the search box to filter mods later. Toggle in BOI to enable/disable. To uninstall, uncheck then delete from <code>/Mods/</code>. === Raw BepInEx === [[BepInPlugins]] and [[Partiality|partmods]] go into <code>Rain World/BepInEx/plugins/</code>. [[MonoMod Patches]] go into <code>Rain World/BepInEx/monomod/</code> (they need to be renamed to template <code>AssemblyCSharp.[modname].mm.dll</code>). [[Preloader Patchers]] go into <code>Rain World/BepInEx/patchers/</code>. To uninstall, delete mod .dll file from respective active folder. == Installing region packs == For this, you'll need to have completed [[#Installing the modloader]]. To install custom regions, you will first need [[CRS]] and all of its dependencies. === In-game installer === From CRS Config menu, you can easily install most publicly released region mods in one click from "browse RainDB" tab. You may need to relaunch the game to reload dependency DLLs after everything is done downloading. === Manual === This is useful for installing regpacks that are not publicly available. # Download the regpack archive # Without changing folder structure, unpack it into <code>Rain World/Mods/CustomResources/</code> so that the resulting folders look like the following: <syntaxhighlight> Rain World/ L__ Mods/ L__ CustomResources/ L__ YourRegionMod/ L___ Assets/ L___ World/ L___ Levels/ L___ packInfo.json L___ thumb.png </syntaxhighlight> == Installing standalone mods == [[Standalone Mods]] are installed by folder merging. They usually come as an archive with a folder called <code>Rain World</code> in it. To install a standalone mod, unpack its archive and drag Rain World subfolder from it onto the main game folder, select "replace all files". To uninstall a standalone mod, go to Steam library, right click on Rain World, select Properties -> Local files -> Verify integrity of game files. If you are not on steam, you will probably need to wipe and reinstall your game. == Sprite packs == Sprite packs are asset bundles containing sprite replacements for slugcats. To use them, you need # An asset loader. It can be: #* [[Custom Sprites Loader]] aka CSL (Partmod<!--, instances are additionally bundled with RegionKit-->) #* [[CustomAssets]] (MMPatch) # A character customizer mod. It can be: #* [[FancySlugcats]] (partmod) #* [[ShinyRat]] (Bepinex plugin) Sprite packs usually come with their own READMEs. * When using CustomAssets, the usual way to install a sprite pack is by folder merge. * When using CSL, the sprites can be put into <code>ModConfigs/CustomSpritesLoader/Load/</code> or any subfolder inside it (you need to run the game once with CSL enabled for the folder to be generated). After the sprites have been put into their place, run the game and head into your character customizer's config menu to set sprite names. * When using FancySlugcats, be sure to exactly input sprite names as shown in your sprite pack's README. If you input a name wrong, the game will freeze on start. FancySlugcats is terminally incompatible with some custom character mods. * ShinyRat is crash resistant and more or less works with most character mods. <!--[[Category:End user guides]]--> 0e7b2801977afbd5d0ee1378eb26c22601c115a4 248 202 2022-08-18T08:48:40Z Thalber 3 /* Installing the modloader */ replaced dupes with links wikitext text/x-wiki {{Cleanup}} This page contains instructions on how to install and use available mods, as well as modloaders. Most mods and tools are available on [https://raindb.net/ rainDB] or in <nowiki>#modding-releases</nowiki> channel of [https://discord.gg/rainworld RW Discord server]. When installing a mod, refer to its README file if there is one. You can see what type a mod is by hovering a square icon next to its name on RainDB. == Installing the modloader == === BOI === [[BOI]] is a user-friendly graphical interface for BepInEx. It is not necessary for installing mods, but is useful for people who are not very experienced with computers. To install, follow instructions at [[BOI#Installation]]. Things to note: * Older versions of BOI use a different dialog window for path selection, that one requires you to select the folder game exe is in, not the exe itself. === Bepinex === There are two ways of installing BepInEx: # '''Through BOI''': In the <code>Download Mods / Install BepInEx</code> subwindow, you can press "Install Bepinex". Wait 15 to 20 seconds until the window unfreezes. # '''Manually''' (this is useful if you are not using BOI for some reason): To install, follow instructions at [[BepInEx#Installation]]. === Realm === [[Realm]] is an alternative BepInEx package. It features in-game mod manager menu and some quick reload capabilities. Realm is incompatible with BOI and you should not use the two together. If you plan on using Realm, do not install standard BepInEx. To install, follow instructions at [[Realm#Installation]]. == Installing code mods == === BepInEx + BOI === Mod <code>.dll</code> files go into <code>Rain World/Mods/</code>. You can also drag and drop them into BOI modlist. Use Tags field to set notes for your mods, you can use the search box to filter mods later. Toggle in BOI to enable/disable. To uninstall, uncheck then delete from <code>/Mods/</code>. === Raw BepInEx === [[BepInPlugins]] and [[Partiality|partmods]] go into <code>Rain World/BepInEx/plugins/</code>. [[MonoMod Patches]] go into <code>Rain World/BepInEx/monomod/</code> (they need to be renamed to template <code>AssemblyCSharp.[modname].mm.dll</code>). [[Preloader Patchers]] go into <code>Rain World/BepInEx/patchers/</code>. To uninstall, delete mod .dll file from respective active folder. == Installing region packs == For this, you'll need to have completed [[#Installing the modloader]]. To install custom regions, you will first need [[CRS]] and all of its dependencies. === In-game installer === From CRS Config menu, you can easily install most publicly released region mods in one click from "browse RainDB" tab. You may need to relaunch the game to reload dependency DLLs after everything is done downloading. === Manual === This is useful for installing regpacks that are not publicly available. # Download the regpack archive # Without changing folder structure, unpack it into <code>Rain World/Mods/CustomResources/</code> so that the resulting folders look like the following: <syntaxhighlight> Rain World/ L__ Mods/ L__ CustomResources/ L__ YourRegionMod/ L___ Assets/ L___ World/ L___ Levels/ L___ packInfo.json L___ thumb.png </syntaxhighlight> == Installing standalone mods == [[Standalone Mods]] are installed by folder merging. They usually come as an archive with a folder called <code>Rain World</code> in it. To install a standalone mod, unpack its archive and drag Rain World subfolder from it onto the main game folder, select "replace all files". To uninstall a standalone mod, go to Steam library, right click on Rain World, select Properties -> Local files -> Verify integrity of game files. If you are not on steam, you will probably need to wipe and reinstall your game. == Sprite packs == Sprite packs are asset bundles containing sprite replacements for slugcats. To use them, you need # An asset loader. It can be: #* [[Custom Sprites Loader]] aka CSL (Partmod<!--, instances are additionally bundled with RegionKit-->) #* [[CustomAssets]] (MMPatch) # A character customizer mod. It can be: #* [[FancySlugcats]] (partmod) #* [[ShinyRat]] (Bepinex plugin) Sprite packs usually come with their own READMEs. * When using CustomAssets, the usual way to install a sprite pack is by folder merge. * When using CSL, the sprites can be put into <code>ModConfigs/CustomSpritesLoader/Load/</code> or any subfolder inside it (you need to run the game once with CSL enabled for the folder to be generated). After the sprites have been put into their place, run the game and head into your character customizer's config menu to set sprite names. * When using FancySlugcats, be sure to exactly input sprite names as shown in your sprite pack's README. If you input a name wrong, the game will freeze on start. FancySlugcats is terminally incompatible with some custom character mods. * ShinyRat is crash resistant and more or less works with most character mods. <!--[[Category:End user guides]]--> bf72288e3b42f5441cbd111a9a3023b79e5f9516 249 248 2022-08-18T08:55:01Z Thalber 3 /* Installing region packs */ syntaxhighlight to pre wikitext text/x-wiki {{Cleanup}} This page contains instructions on how to install and use available mods, as well as modloaders. Most mods and tools are available on [https://raindb.net/ rainDB] or in <nowiki>#modding-releases</nowiki> channel of [https://discord.gg/rainworld RW Discord server]. When installing a mod, refer to its README file if there is one. You can see what type a mod is by hovering a square icon next to its name on RainDB. == Installing the modloader == === BOI === [[BOI]] is a user-friendly graphical interface for BepInEx. It is not necessary for installing mods, but is useful for people who are not very experienced with computers. To install, follow instructions at [[BOI#Installation]]. Things to note: * Older versions of BOI use a different dialog window for path selection, that one requires you to select the folder game exe is in, not the exe itself. === Bepinex === There are two ways of installing BepInEx: # '''Through BOI''': In the <code>Download Mods / Install BepInEx</code> subwindow, you can press "Install Bepinex". Wait 15 to 20 seconds until the window unfreezes. # '''Manually''' (this is useful if you are not using BOI for some reason): To install, follow instructions at [[BepInEx#Installation]]. === Realm === [[Realm]] is an alternative BepInEx package. It features in-game mod manager menu and some quick reload capabilities. Realm is incompatible with BOI and you should not use the two together. If you plan on using Realm, do not install standard BepInEx. To install, follow instructions at [[Realm#Installation]]. == Installing code mods == === BepInEx + BOI === Mod <code>.dll</code> files go into <code>Rain World/Mods/</code>. You can also drag and drop them into BOI modlist. Use Tags field to set notes for your mods, you can use the search box to filter mods later. Toggle in BOI to enable/disable. To uninstall, uncheck then delete from <code>/Mods/</code>. === Raw BepInEx === [[BepInPlugins]] and [[Partiality|partmods]] go into <code>Rain World/BepInEx/plugins/</code>. [[MonoMod Patches]] go into <code>Rain World/BepInEx/monomod/</code> (they need to be renamed to template <code>AssemblyCSharp.[modname].mm.dll</code>). [[Preloader Patchers]] go into <code>Rain World/BepInEx/patchers/</code>. To uninstall, delete mod .dll file from respective active folder. == Installing region packs == For this, you'll need to have completed [[#Installing the modloader]]. To install custom regions, you will first need [[CRS]] and all of its dependencies. === In-game installer === From CRS Config menu, you can easily install most publicly released region mods in one click from "browse RainDB" tab. You may need to relaunch the game to reload dependency DLLs after everything is done downloading. === Manual === This is useful for installing regpacks that are not publicly available. # Download the regpack archive # Without changing folder structure, unpack it into <code>Rain World/Mods/CustomResources/</code> so that the resulting folders look like the following: <pre> Rain World/ L__ Mods/ L__ CustomResources/ L__ YourRegionMod/ L___ Assets/ L___ World/ L___ Levels/ L___ packInfo.json L___ thumb.png </pre> == Installing standalone mods == [[Standalone Mods]] are installed by folder merging. They usually come as an archive with a folder called <code>Rain World</code> in it. To install a standalone mod, unpack its archive and drag Rain World subfolder from it onto the main game folder, select "replace all files". To uninstall a standalone mod, go to Steam library, right click on Rain World, select Properties -> Local files -> Verify integrity of game files. If you are not on steam, you will probably need to wipe and reinstall your game. == Sprite packs == Sprite packs are asset bundles containing sprite replacements for slugcats. To use them, you need # An asset loader. It can be: #* [[Custom Sprites Loader]] aka CSL (Partmod<!--, instances are additionally bundled with RegionKit-->) #* [[CustomAssets]] (MMPatch) # A character customizer mod. It can be: #* [[FancySlugcats]] (partmod) #* [[ShinyRat]] (Bepinex plugin) Sprite packs usually come with their own READMEs. * When using CustomAssets, the usual way to install a sprite pack is by folder merge. * When using CSL, the sprites can be put into <code>ModConfigs/CustomSpritesLoader/Load/</code> or any subfolder inside it (you need to run the game once with CSL enabled for the folder to be generated). After the sprites have been put into their place, run the game and head into your character customizer's config menu to set sprite names. * When using FancySlugcats, be sure to exactly input sprite names as shown in your sprite pack's README. If you input a name wrong, the game will freeze on start. FancySlugcats is terminally incompatible with some custom character mods. * ShinyRat is crash resistant and more or less works with most character mods. <!--[[Category:End user guides]]--> 88d1071f5a561de8df90d750e5c1d2c47204da4b File:dnspy.png 6 125 203 2022-08-12T10:51:35Z Cashewww 2 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 Code Environments 0 126 204 2022-08-12T11:23:39Z Cashewww 2 started page for setting up code tools wikitext text/x-wiki {{Cleanup}} == Reading Code == To mod Rain World, you need to be able to read the game's code. As it was written in C# and compiled against .NET Framework 3.5, you will need to use a decompiler to view the code. Remember that it is illegal to redistribute the game's code; decompiled copies are for your own use only. A few decompiler options are available to you, including: === dnSpy === [[File:dnspy.png|thumb|dnSpy being used to view the decompiled code of a mod's method in C#.]] '''Warning:''' in recent years, trojans have been released disguised as dnSpy, targetting security researchers. You should only download dnSpy from dnSpy's GitHub repository ([https://github.com/dnSpy/dnSpy/releases/latest dnSpy/dnSpy]). DnSpy is a .NET decompiler application that is designed to look visually similar to Visual Studio. It's popular with Rain World modders, modders of other .NET-based games, and security researchers. 32-bit and 64-bit Windows downloads can be found [https://github.com/dnSpy/dnSpy/releases/latest here]. === ILSpy === ILSpy is a .NET decompiler backend. There are many frontends, often in the form of extensions for Visual Studio and Visual Studio Code. There's also a frontend built into JetBrains Rider. == Writing Code == Most Rain World code modders use Visual Studio to write their code. This section will go over how to set up Visual Studio for Rain World modding. However, Visual Studio is limited to Windows, so you may find that Linux- and Mac-compatible options like [https://www.jetbrains.com/rider/ JetBrains Rider] and [https://code.visualstudio.com/ Visual Studio Code] are better suited to your use-case. 4c92117128899582344980f2f46fdbb5e37421c9 205 204 2022-08-12T11:34:58Z Cashewww 2 Cashewww moved page [[Setting Up a Code Environment]] to [[Code Environments]] without leaving a redirect wikitext text/x-wiki {{Cleanup}} == Reading Code == To mod Rain World, you need to be able to read the game's code. As it was written in C# and compiled against .NET Framework 3.5, you will need to use a decompiler to view the code. Remember that it is illegal to redistribute the game's code; decompiled copies are for your own use only. A few decompiler options are available to you, including: === dnSpy === [[File:dnspy.png|thumb|dnSpy being used to view the decompiled code of a mod's method in C#.]] '''Warning:''' in recent years, trojans have been released disguised as dnSpy, targetting security researchers. You should only download dnSpy from dnSpy's GitHub repository ([https://github.com/dnSpy/dnSpy/releases/latest dnSpy/dnSpy]). DnSpy is a .NET decompiler application that is designed to look visually similar to Visual Studio. It's popular with Rain World modders, modders of other .NET-based games, and security researchers. 32-bit and 64-bit Windows downloads can be found [https://github.com/dnSpy/dnSpy/releases/latest here]. === ILSpy === ILSpy is a .NET decompiler backend. There are many frontends, often in the form of extensions for Visual Studio and Visual Studio Code. There's also a frontend built into JetBrains Rider. == Writing Code == Most Rain World code modders use Visual Studio to write their code. This section will go over how to set up Visual Studio for Rain World modding. However, Visual Studio is limited to Windows, so you may find that Linux- and Mac-compatible options like [https://www.jetbrains.com/rider/ JetBrains Rider] and [https://code.visualstudio.com/ Visual Studio Code] are better suited to your use-case. 4c92117128899582344980f2f46fdbb5e37421c9 219 205 2022-08-16T07:36:42Z Thalber 3 wikitext text/x-wiki {{Cleanup}} == Reading Code == To mod Rain World, you need to be able to read the game's code. As it was written in C# and compiled against .NET Framework 3.5, you will need to use a decompiler to view the code. Remember that it is illegal to redistribute the game's code; decompiled copies are for your own use only. A few decompiler options are available to you, including: === dnSpy === [[File:dnspy.png|thumb|dnSpy being used to view the decompiled code of a mod's method in C#.]] '''Warning:''' in recent years, trojans have been released disguised as dnSpy, targetting security researchers. You should only download dnSpy from dnSpy's GitHub repository ([https://github.com/dnSpy/dnSpy/releases/latest dnSpy/dnSpy]). DnSpy is a .NET decompiler application that is designed to look visually similar to Visual Studio. It's popular with Rain World modders, modders of other .NET-based games, and security researchers. 32-bit and 64-bit Windows downloads can be found [https://github.com/dnSpy/dnSpy/releases/latest here]. dnSpy provides the most user convenience out of the options listed here, with handy usage analyzer and other inspection tools. It is, however, === ILSpy === ILSpy is a .NET decompiler backend. There are many frontends, often in the form of extensions for Visual Studio and Visual Studio Code. There's also a frontend built into JetBrains Rider. === ICsharpCode.Decompiler === Starting with version 2022, Visual Studio comes with its own decompiler: you can inspect classes from your reference libraries. == Writing Code == {{todo}} Most Rain World code modders use Visual Studio to write their code. This section will go over how to set up Visual Studio for Rain World modding. However, Visual Studio is limited to Windows, so you may find that Linux- and Mac-compatible options like [https://www.jetbrains.com/rider/ JetBrains Rider] and [https://code.visualstudio.com/ Visual Studio Code] are better suited to your use-case. === Installing Visual Studio === # Download the ''installer'' for latest version of VS [https://visualstudio.microsoft.com/downloads/ here]. Run it. # From the installer, create a new install of VS. In workload selection menu, make sure you have ".NET desktop development" selected. In Individual components, search for ".NET Framework 3.5 targeting pack" and enable it too. # Start the installation, wait for it to finish. [[File:CodeEnv-VSInstaller.png|none|thumb|alt=Visual Studio installer screen|Visual Studio installer screen]] === Creating a Visual Studio project === When creating a project for a rain world mod, you will need to a '''class library''' targeting '''.NET Framework 3.5'''. There are some problems you may encounter on this step. * Occasionally Visual Studio refuses to display targeting Framework 3.5 as an option. The pattern is unclear. * Creating a project targeting fw3.5 from Visual Studio's GUI causes it to be made with old <code>.csproj</code> file format (msbuild 2003), which restricts some features and is generally more messy. '''Steps to tell if the project is in older format''': ** Open the file in a text editor ** If it looks like a pile of piss-stained spaghetti and has <code><Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"></code> around the beginning, it's old. Thus it's recommended to create project files from the command line with <code>dotnet new</code>: [[File:CodeEnv-DotnetCLI.png|none|thumb|alt=Creating a project with dotnet CLI|Creating a project with dotnet CLI]] Then open the resulting .csproj in Visual Studio, double click the project name in solution structure, and change the first block to have tags with following values: {| class="wikitable" |- ! Tag !! Value |- | TargetFramework || net35 |- | ImplicitUsings || disable |- | Nullable || disable |- | LangVersion || latest |} === Adding references === To compile mods and access the game code, you need to add some assemblies to your project as ''references''. To do this, you can * Use <code>Project -> Add project reference...</code> in VS. * Manually add <code>Include</code>s to your .csproj. For all mods, it is a good idea to reference: {|class="wikitable" |- ! Assembly !! Contains !! Notes |- | RainWorld_Data/Managed/AssemblyCSharp.dll || All of the vanilla game code || Use [https://github.com/Reinms/Stubber-Publicizer this tool] to remove accessibility restrictions |- | RainWorld_Data/Managed/UnityEngine.dll || Unity API methods |- | BepInEx/core/BepInEx.dll || [[BepInEx]] api |- | BepInEx/plugins/PartialityWrapper/HOOKS-Assembly-CSharp.dll || Hookgen events for methods in Assembly-CSharp for easily attaching code |- | BepInEx/core/MonoMod.RuntimeDetour || Classes and methods necessary for applying manual detours/hooks |- | BepInEx/core/MonoMod.Utils.dll || Classes and methods necessary for applying IL hooks, as well as some additional functionality |} Additionally, if you want to use a dependency mod, you will likely need to reference it too. If you are planning to share your code at some point, it is recommended that you set up your references without using absolute paths on your PC. This can be done in few ways: * Copying the reference files to a folder inside or near the project folder. * Setting up a folder symlink from somewhere in the project to a reference dir. On Windows, you can use https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink mklink /J] from command prompt. In either case, you should [https://git-scm.com/docs/gitignore gitignore] references if they happen to be in a repo to avoid redistributing others' code. [[Category:Code Mods]] bc6039a202bf3333d108bd4b5cc72c316febcbef 221 219 2022-08-17T16:00:28Z Thalber 3 /* Adding references */ link typo wikitext text/x-wiki {{Cleanup}} == Reading Code == To mod Rain World, you need to be able to read the game's code. As it was written in C# and compiled against .NET Framework 3.5, you will need to use a decompiler to view the code. Remember that it is illegal to redistribute the game's code; decompiled copies are for your own use only. A few decompiler options are available to you, including: === dnSpy === [[File:dnspy.png|thumb|dnSpy being used to view the decompiled code of a mod's method in C#.]] '''Warning:''' in recent years, trojans have been released disguised as dnSpy, targetting security researchers. You should only download dnSpy from dnSpy's GitHub repository ([https://github.com/dnSpy/dnSpy/releases/latest dnSpy/dnSpy]). DnSpy is a .NET decompiler application that is designed to look visually similar to Visual Studio. It's popular with Rain World modders, modders of other .NET-based games, and security researchers. 32-bit and 64-bit Windows downloads can be found [https://github.com/dnSpy/dnSpy/releases/latest here]. dnSpy provides the most user convenience out of the options listed here, with handy usage analyzer and other inspection tools. It is, however, === ILSpy === ILSpy is a .NET decompiler backend. There are many frontends, often in the form of extensions for Visual Studio and Visual Studio Code. There's also a frontend built into JetBrains Rider. === ICsharpCode.Decompiler === Starting with version 2022, Visual Studio comes with its own decompiler: you can inspect classes from your reference libraries. == Writing Code == {{todo}} Most Rain World code modders use Visual Studio to write their code. This section will go over how to set up Visual Studio for Rain World modding. However, Visual Studio is limited to Windows, so you may find that Linux- and Mac-compatible options like [https://www.jetbrains.com/rider/ JetBrains Rider] and [https://code.visualstudio.com/ Visual Studio Code] are better suited to your use-case. === Installing Visual Studio === # Download the ''installer'' for latest version of VS [https://visualstudio.microsoft.com/downloads/ here]. Run it. # From the installer, create a new install of VS. In workload selection menu, make sure you have ".NET desktop development" selected. In Individual components, search for ".NET Framework 3.5 targeting pack" and enable it too. # Start the installation, wait for it to finish. [[File:CodeEnv-VSInstaller.png|none|thumb|alt=Visual Studio installer screen|Visual Studio installer screen]] === Creating a Visual Studio project === When creating a project for a rain world mod, you will need to a '''class library''' targeting '''.NET Framework 3.5'''. There are some problems you may encounter on this step. * Occasionally Visual Studio refuses to display targeting Framework 3.5 as an option. The pattern is unclear. * Creating a project targeting fw3.5 from Visual Studio's GUI causes it to be made with old <code>.csproj</code> file format (msbuild 2003), which restricts some features and is generally more messy. '''Steps to tell if the project is in older format''': ** Open the file in a text editor ** If it looks like a pile of piss-stained spaghetti and has <code><Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"></code> around the beginning, it's old. Thus it's recommended to create project files from the command line with <code>dotnet new</code>: [[File:CodeEnv-DotnetCLI.png|none|thumb|alt=Creating a project with dotnet CLI|Creating a project with dotnet CLI]] Then open the resulting .csproj in Visual Studio, double click the project name in solution structure, and change the first block to have tags with following values: {| class="wikitable" |- ! Tag !! Value |- | TargetFramework || net35 |- | ImplicitUsings || disable |- | Nullable || disable |- | LangVersion || latest |} === Adding references === To compile mods and access the game code, you need to add some assemblies to your project as ''references''. To do this, you can * Use <code>Project -> Add project reference...</code> in VS. * Manually add <code>Include</code>s to your .csproj. For all mods, it is a good idea to reference: {|class="wikitable" |- ! Assembly !! Contains !! Notes |- | RainWorld_Data/Managed/AssemblyCSharp.dll || All of the vanilla game code || Use [https://github.com/Reinms/Stubber-Publicizer this tool] to remove accessibility restrictions |- | RainWorld_Data/Managed/UnityEngine.dll || Unity API methods |- | BepInEx/core/BepInEx.dll || [[BepInEx]] api |- | BepInEx/plugins/PartialityWrapper/HOOKS-Assembly-CSharp.dll || Hookgen events for methods in Assembly-CSharp for easily attaching code |- | BepInEx/core/MonoMod.RuntimeDetour || Classes and methods necessary for applying manual detours/hooks |- | BepInEx/core/MonoMod.Utils.dll || Classes and methods necessary for applying IL hooks, as well as some additional functionality |} Additionally, if you want to use a dependency mod, you will likely need to reference it too. If you are planning to share your code at some point, it is recommended that you set up your references without using absolute paths on your PC. This can be done in few ways: * Copying the reference files to a folder inside or near the project folder. * Setting up a folder symlink from somewhere in the project to a reference dir. On Windows, you can use [https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink mklink /J] from command prompt. In either case, you should [https://git-scm.com/docs/gitignore gitignore] references if they happen to be in a repo to avoid redistributing others' code. [[Category:Code Mods]] 0634c4cce84fa43dd46aa92399277066fc166d56 224 221 2022-08-17T17:03:28Z Thalber 3 /* Writing Code */ wikitext text/x-wiki {{Cleanup}} == Reading Code == To mod Rain World, you need to be able to read the game's code. As it was written in C# and compiled against .NET Framework 3.5, you will need to use a decompiler to view the code. Remember that it is illegal to redistribute the game's code; decompiled copies are for your own use only. A few decompiler options are available to you, including: === dnSpy === [[File:dnspy.png|thumb|dnSpy being used to view the decompiled code of a mod's method in C#.]] '''Warning:''' in recent years, trojans have been released disguised as dnSpy, targetting security researchers. You should only download dnSpy from dnSpy's GitHub repository ([https://github.com/dnSpy/dnSpy/releases/latest dnSpy/dnSpy]). DnSpy is a .NET decompiler application that is designed to look visually similar to Visual Studio. It's popular with Rain World modders, modders of other .NET-based games, and security researchers. 32-bit and 64-bit Windows downloads can be found [https://github.com/dnSpy/dnSpy/releases/latest here]. dnSpy provides the most user convenience out of the options listed here, with handy usage analyzer and other inspection tools. It is, however, === ILSpy === ILSpy is a .NET decompiler backend. There are many frontends, often in the form of extensions for Visual Studio and Visual Studio Code. There's also a frontend built into JetBrains Rider. === ICsharpCode.Decompiler === Starting with version 2022, Visual Studio comes with its own decompiler: you can inspect classes from your reference libraries. == Writing Code == Most Rain World code modders use Visual Studio to write their code. This section will go over how to set up Visual Studio for Rain World modding. However, Visual Studio is limited to Windows, so you may find that Linux- and Mac-compatible options like [https://www.jetbrains.com/rider/ JetBrains Rider] and [https://code.visualstudio.com/ Visual Studio Code] are better suited to your use-case. === Installing Visual Studio === # Download the ''installer'' for latest version of VS [https://visualstudio.microsoft.com/downloads/ here]. Run it. # From the installer, create a new install of VS. In workload selection menu, make sure you have ".NET desktop development" selected. In Individual components, search for ".NET Framework 3.5 targeting pack" and enable it too. # Start the installation, wait for it to finish. [[File:CodeEnv-VSInstaller.png|none|thumb|alt=Visual Studio installer screen|Visual Studio installer screen]] === Creating a Visual Studio project === When creating a project for a rain world mod, you will need to a '''class library''' targeting '''.NET Framework 3.5'''. There are some problems you may encounter on this step. * Occasionally Visual Studio refuses to display targeting Framework 3.5 as an option. The pattern is unclear. * Creating a project targeting fw3.5 from Visual Studio's GUI causes it to be made with old <code>.csproj</code> file format (msbuild 2003), which restricts some features and is generally more messy. '''Steps to tell if the project is in older format''': ** Open the file in a text editor ** If it looks like a pile of piss-soaked spaghetti and has <code><Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"></code> around the beginning, it's old. Thus it's recommended to create project files from the command line with <code>dotnet new</code>: [[File:CodeEnv-DotnetCLI.png|none|thumb|alt=Creating a project with dotnet CLI|Creating a project with dotnet CLI]] Then open the resulting .csproj in Visual Studio, double click the project name in solution structure, and change the first block to have tags with following values: {| class="wikitable" |- ! Tag !! Value |- | TargetFramework || net35 |- | ImplicitUsings || disable |- | Nullable || disable |- | LangVersion || latest |} === Adding references === To compile mods and access the game code, you need to add some assemblies to your project as ''references''. To do this, you can * Use <code>Project -> Add project reference...</code> in VS. * Manually add <code>Include</code>s to your .csproj. For all mods, it is a good idea to reference: {|class="wikitable" |- ! Assembly !! Contains !! Notes |- | RainWorld_Data/Managed/AssemblyCSharp.dll || All of the vanilla game code || Use [https://github.com/Reinms/Stubber-Publicizer this tool] to remove accessibility restrictions |- | RainWorld_Data/Managed/UnityEngine.dll || Unity API methods |- | BepInEx/core/BepInEx.dll || [[BepInEx]] api |- | BepInEx/plugins/PartialityWrapper/HOOKS-Assembly-CSharp.dll || Hookgen events for methods in Assembly-CSharp for easily attaching code |- | BepInEx/core/MonoMod.RuntimeDetour || Classes and methods necessary for applying manual detours/hooks |- | BepInEx/core/MonoMod.Utils.dll || Classes and methods necessary for applying IL hooks, as well as some additional functionality |} Additionally, if you want to use a dependency mod, you will likely need to reference it too. If you are planning to share your code at some point, it is recommended that you set up your references without using absolute paths on your PC. This can be done in few ways: * Copying the reference files to a folder inside or near the project folder. * Setting up a folder symlink from somewhere in the project to a reference dir. On Windows, you can use [https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink mklink /J] from command prompt. In either case, you should [https://git-scm.com/docs/gitignore gitignore] references if they happen to be in a repo to avoid redistributing others' code. === Building === After you've wrote something, you will naturally want to run it and see if it works. As of now, there is no way of attaching a debugger to Rain World process, and version of Mono packed with the game does not load .pdb files. Thus you should always build your mods on Release configuration, even if you're mid-development. To load a mod into the game, you need to copy its assembly into respective BepInEx active folder (<code>BepInEx/plugins/</code> unless you are making an [[MonoMod Patches|mmpatch]]). You can automate this step by using a build event: * In Project properties view in VS, find Build Events, and into Post-build insert one of these: ** Unconditional build event with hardcoded destination: <code>copy /Y "$(TargetPath)" "Path/to/your/plugins/folder/here"</code> ** Copies files into a path defined by environment variable <code>RWMods</code> (if it exists): <code>if defined RWMods (copy /Y "$(TargetPath)" "%RWMods%")</code> === Testing and Debugging === {{todo}} As mentioned, attaching a debugger to the game is currently not an option. This sections will contain several tips on mitigating the pain. * You can enable a separate console window for BepInEx output in <code>BepInEx/config/bepinex.cfg</code>. * From a [[BepInPlugins|BepInEx plugin]], use <code>Logger</code> property. If you need to lend access to your logger to different class, use something like: <codehighlight lang="csharp"> public class MyPlugin : Baseunityplugin { public MyPlugin() { __me = new(this); } //WeakReference to not prevent garbage collection private static WeakReference __me; public static MyPlugin ME => __me?.target as MyPlugin; //wrapper property. If you don't need a static member, just do this and pass plugin instance around. public ManualLogSource Logger_p => Logger; } //... MyPlugin.ME.Logger_p.Log(); </codehighlight> * [https://github.com/casheww/RW-ToolBox/releases/latest This plugin] by casheww might help you with specific tasks [[Category:Code Mods]] d06769999f72dd90bf3fa79c62a912ae2c7d19c8 225 224 2022-08-17T17:19:16Z Thalber 3 wikitext text/x-wiki {{Cleanup}} == Reading Code == To mod Rain World, you need to be able to read the game's code. As it was written in C# and compiled against .NET Framework 3.5, you will need to use a decompiler to view the code. Remember that it is illegal to redistribute the game's code; decompiled copies are for your own use only. A few decompiler options are available to you, including: === dnSpy === [[File:dnspy.png|thumb|dnSpy being used to view the decompiled code of a mod's method in C#.]] '''Warning:''' in recent years, trojans have been released disguised as dnSpy, targetting security researchers. You should only download dnSpy from dnSpy's GitHub repository ([https://github.com/dnSpy/dnSpy/releases/latest dnSpy/dnSpy]). DnSpy is a .NET decompiler application that is designed to look visually similar to Visual Studio. It's popular with Rain World modders, modders of other .NET-based games, and security researchers. 32-bit and 64-bit Windows downloads can be found [https://github.com/dnSpy/dnSpy/releases/latest here]. dnSpy provides the most user convenience out of the options listed here, with handy usage analyzer and other inspection tools. It is, however, === ILSpy === ILSpy is a .NET decompiler backend. There are many frontends, often in the form of extensions for Visual Studio and Visual Studio Code. There's also a frontend built into JetBrains Rider. === ICsharpCode.Decompiler === Starting with version 2022, Visual Studio comes with its own decompiler: you can inspect classes from your reference libraries. == Writing Code == Most Rain World code modders use Visual Studio to write their code. This section will go over how to set up Visual Studio for Rain World modding. However, Visual Studio is limited to Windows, so you may find that Linux- and Mac-compatible options like [https://www.jetbrains.com/rider/ JetBrains Rider] and [https://code.visualstudio.com/ Visual Studio Code] are better suited to your use-case. === Installing Visual Studio === # Download the ''installer'' for latest version of VS [https://visualstudio.microsoft.com/downloads/ here]. Run it. # From the installer, create a new install of VS. In workload selection menu, make sure you have ".NET desktop development" selected. In Individual components, search for ".NET Framework 3.5 targeting pack" and enable it too. # Start the installation, wait for it to finish. [[File:CodeEnv-VSInstaller.png|none|thumb|alt=Visual Studio installer screen|Visual Studio installer screen]] === Creating a Visual Studio project === When creating a project for a rain world mod, you will need to a '''class library''' targeting '''.NET Framework 3.5'''. There are some problems you may encounter on this step. * Occasionally Visual Studio refuses to display targeting Framework 3.5 as an option. The pattern is unclear. * Creating a project targeting fw3.5 from Visual Studio's GUI causes it to be made with old <code>.csproj</code> file format (msbuild 2003), which restricts some features and is generally more messy. '''Steps to tell if the project is in older format''': ** Open the file in a text editor ** If it looks like a pile of piss-soaked spaghetti and has <code>Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"</code> around the beginning, it's old. Thus it's recommended to create project files from the command line with <code>dotnet new</code>: [[File:CodeEnv-DotnetCLI.png|none|thumb|alt=Creating a project with dotnet CLI|Creating a project with dotnet CLI]] Then open the resulting .csproj in Visual Studio, double click the project name in solution structure, and change the first block to have tags with following values: {| class="wikitable" |- ! Tag !! Value |- | TargetFramework || net35 |- | ImplicitUsings || disable |- | Nullable || disable |- | LangVersion || latest |} === Adding references === To compile mods and access the game code, you need to add some assemblies to your project as ''references''. To do this, you can * Use <code>Project -> Add project reference...</code> in VS. * Manually add <code>Include</code>s to your .csproj. For all mods, it is a good idea to reference: {|class="wikitable" |- ! Assembly !! Contains !! Notes |- | RainWorld_Data/Managed/AssemblyCSharp.dll || All of the vanilla game code || Use [https://github.com/Reinms/Stubber-Publicizer this tool] to remove accessibility restrictions |- | RainWorld_Data/Managed/UnityEngine.dll || Unity API methods |- | BepInEx/core/BepInEx.dll || [[BepInEx]] api |- | BepInEx/plugins/PartialityWrapper/HOOKS-Assembly-CSharp.dll || Hookgen events for methods in Assembly-CSharp for easily attaching code |- | BepInEx/core/MonoMod.RuntimeDetour || Classes and methods necessary for applying manual detours/hooks |- | BepInEx/core/MonoMod.Utils.dll || Classes and methods necessary for applying IL hooks, as well as some additional functionality |} Additionally, if you want to use a dependency mod, you will likely need to reference it too. If you are planning to share your code at some point, it is recommended that you set up your references without using absolute paths on your PC. This can be done in few ways: * Copying the reference files to a folder inside or near the project folder. * Setting up a folder symlink from somewhere in the project to a reference dir. On Windows, you can use [https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink mklink /J] from command prompt. In either case, you should [https://git-scm.com/docs/gitignore gitignore] references if they happen to be in a repo to avoid redistributing others' code. === Building === After you've wrote something, you will naturally want to run it and see if it works. As of now, there is no way of attaching a debugger to Rain World process, and version of Mono packed with the game does not load .pdb files. Thus you should always build your mods on Release configuration, even if you're mid-development. To load a mod into the game, you need to copy its assembly into respective BepInEx active folder (<code>BepInEx/plugins/</code> unless you are making an [[MonoMod Patches|mmpatch]]). You can automate this step by using a build event: * In Project properties view in VS, find Build Events, and into Post-build insert one of these: ** Unconditional build event with hardcoded destination: <code>copy /Y "$(TargetPath)" "Path/to/your/plugins/folder/here"</code> ** Copies files into a path defined by environment variable <code>RWMods</code> (if it exists): <code>if defined RWMods (copy /Y "$(TargetPath)" "%RWMods%")</code> === Testing and Debugging === {{todo}} As mentioned, attaching a debugger to the game is currently not an option. This sections will contain several tips on mitigating the pain. * You can enable a separate console window for BepInEx output in <code>BepInEx/config/bepinex.cfg</code>. * From a [[BepInPlugins|BepInEx plugin]], use <code>Logger</code> property. If you need to lend access to your logger to different class, use something like: <syntaxhighlight lang="csharp"> public class MyPlugin : Baseunityplugin { public MyPlugin() { __me = new(this); } //using WeakReference to allow garbage collection private static WeakReference __me; public static MyPlugin ME => __me?.target as MyPlugin; //wrapper property. If you don't need a static member, just do this and pass plugin instance around. public ManualLogSource Logger_p => Logger; } //... MyPlugin.ME.Logger_p.Log(); </syntaxhighlight> * [https://github.com/casheww/RW-ToolBox/releases/latest This plugin] by casheww might help you with specific tasks [[Category:Code Mods]] c1c3aab840d78d5ed548dc37b18d2ff96e0a9821 226 225 2022-08-17T17:23:11Z Thalber 3 /* Building */ wikitext text/x-wiki {{Cleanup}} == Reading Code == To mod Rain World, you need to be able to read the game's code. As it was written in C# and compiled against .NET Framework 3.5, you will need to use a decompiler to view the code. Remember that it is illegal to redistribute the game's code; decompiled copies are for your own use only. A few decompiler options are available to you, including: === dnSpy === [[File:dnspy.png|thumb|dnSpy being used to view the decompiled code of a mod's method in C#.]] '''Warning:''' in recent years, trojans have been released disguised as dnSpy, targetting security researchers. You should only download dnSpy from dnSpy's GitHub repository ([https://github.com/dnSpy/dnSpy/releases/latest dnSpy/dnSpy]). DnSpy is a .NET decompiler application that is designed to look visually similar to Visual Studio. It's popular with Rain World modders, modders of other .NET-based games, and security researchers. 32-bit and 64-bit Windows downloads can be found [https://github.com/dnSpy/dnSpy/releases/latest here]. dnSpy provides the most user convenience out of the options listed here, with handy usage analyzer and other inspection tools. It is, however, === ILSpy === ILSpy is a .NET decompiler backend. There are many frontends, often in the form of extensions for Visual Studio and Visual Studio Code. There's also a frontend built into JetBrains Rider. === ICsharpCode.Decompiler === Starting with version 2022, Visual Studio comes with its own decompiler: you can inspect classes from your reference libraries. == Writing Code == Most Rain World code modders use Visual Studio to write their code. This section will go over how to set up Visual Studio for Rain World modding. However, Visual Studio is limited to Windows, so you may find that Linux- and Mac-compatible options like [https://www.jetbrains.com/rider/ JetBrains Rider] and [https://code.visualstudio.com/ Visual Studio Code] are better suited to your use-case. === Installing Visual Studio === # Download the ''installer'' for latest version of VS [https://visualstudio.microsoft.com/downloads/ here]. Run it. # From the installer, create a new install of VS. In workload selection menu, make sure you have ".NET desktop development" selected. In Individual components, search for ".NET Framework 3.5 targeting pack" and enable it too. # Start the installation, wait for it to finish. [[File:CodeEnv-VSInstaller.png|none|thumb|alt=Visual Studio installer screen|Visual Studio installer screen]] === Creating a Visual Studio project === When creating a project for a rain world mod, you will need to a '''class library''' targeting '''.NET Framework 3.5'''. There are some problems you may encounter on this step. * Occasionally Visual Studio refuses to display targeting Framework 3.5 as an option. The pattern is unclear. * Creating a project targeting fw3.5 from Visual Studio's GUI causes it to be made with old <code>.csproj</code> file format (msbuild 2003), which restricts some features and is generally more messy. '''Steps to tell if the project is in older format''': ** Open the file in a text editor ** If it looks like a pile of piss-soaked spaghetti and has <code>Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"</code> around the beginning, it's old. Thus it's recommended to create project files from the command line with <code>dotnet new</code>: [[File:CodeEnv-DotnetCLI.png|none|thumb|alt=Creating a project with dotnet CLI|Creating a project with dotnet CLI]] Then open the resulting .csproj in Visual Studio, double click the project name in solution structure, and change the first block to have tags with following values: {| class="wikitable" |- ! Tag !! Value |- | TargetFramework || net35 |- | ImplicitUsings || disable |- | Nullable || disable |- | LangVersion || latest |} === Adding references === To compile mods and access the game code, you need to add some assemblies to your project as ''references''. To do this, you can * Use <code>Project -> Add project reference...</code> in VS. * Manually add <code>Include</code>s to your .csproj. For all mods, it is a good idea to reference: {|class="wikitable" |- ! Assembly !! Contains !! Notes |- | RainWorld_Data/Managed/AssemblyCSharp.dll || All of the vanilla game code || Use [https://github.com/Reinms/Stubber-Publicizer this tool] to remove accessibility restrictions |- | RainWorld_Data/Managed/UnityEngine.dll || Unity API methods |- | BepInEx/core/BepInEx.dll || [[BepInEx]] api |- | BepInEx/plugins/PartialityWrapper/HOOKS-Assembly-CSharp.dll || Hookgen events for methods in Assembly-CSharp for easily attaching code |- | BepInEx/core/MonoMod.RuntimeDetour || Classes and methods necessary for applying manual detours/hooks |- | BepInEx/core/MonoMod.Utils.dll || Classes and methods necessary for applying IL hooks, as well as some additional functionality |} Additionally, if you want to use a dependency mod, you will likely need to reference it too. If you are planning to share your code at some point, it is recommended that you set up your references without using absolute paths on your PC. This can be done in few ways: * Copying the reference files to a folder inside or near the project folder. * Setting up a folder symlink from somewhere in the project to a reference dir. On Windows, you can use [https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink mklink /J] from command prompt. In either case, you should [https://git-scm.com/docs/gitignore gitignore] references if they happen to be in a repo to avoid redistributing others' code. === Building === After you've wrote something, you will naturally want to run it and see if it works. As of now, there is no way of attaching a debugger to Rain World process, and version of Mono packed with the game does not load .pdb files. Thus you should always build your mods on Release configuration, even if you're mid-development. To load a mod into the game, you need to copy its assembly into respective BepInEx active folder (<code>BepInEx/plugins/</code> unless you are making an [[MonoMod Patches|mmpatch]]). You can automate this step by using a build event: * In Project properties view in VS, find Build Events, and into Post-build insert one of these: ** Unconditional build event with hardcoded destination: <code>copy /Y "$(TargetPath)" "Path/to/your/plugins/folder/here"</code> ** Copies files into a path defined by environment variable <code>RWMods</code> (if it exists): <code>if defined RWMods (copy /Y "$(TargetPath)" "%RWMods%")</code> By default, building a project copies most of its dependencies to the build destination (<code>bin/release/</code>). You can prevent it by selecting desired references in solution explorer, opening properties dock and setting <code>Copy Local</code> to <code>No</code>: [[File:CodeEnv-copyLocal.png|thumb|none|alt=Disabling Copy Local|Disabling Copy Local]] === Testing and Debugging === {{todo}} As mentioned, attaching a debugger to the game is currently not an option. This sections will contain several tips on mitigating the pain. * You can enable a separate console window for BepInEx output in <code>BepInEx/config/bepinex.cfg</code>. * From a [[BepInPlugins|BepInEx plugin]], use <code>Logger</code> property. If you need to lend access to your logger to different class, use something like: <syntaxhighlight lang="csharp"> public class MyPlugin : Baseunityplugin { public MyPlugin() { __me = new(this); } //using WeakReference to allow garbage collection private static WeakReference __me; public static MyPlugin ME => __me?.target as MyPlugin; //wrapper property. If you don't need a static member, just do this and pass plugin instance around. public ManualLogSource Logger_p => Logger; } //... MyPlugin.ME.Logger_p.Log(); </syntaxhighlight> * [https://github.com/casheww/RW-ToolBox/releases/latest This plugin] by casheww might help you with specific tasks [[Category:Code Mods]] a535cd4cfee173c58582d28280e32d230ee14efd 227 226 2022-08-17T17:48:36Z Thalber 3 wikitext text/x-wiki {{Cleanup}} == Reading Code == To mod Rain World, you need to be able to read the game's code. As it was written in C# and compiled against .NET Framework 3.5, you will need to use a decompiler to view the code. Remember that it is illegal to redistribute the game's code; decompiled copies are for your own use only. A few decompiler options are available to you, including: === dnSpy === [[File:dnspy.png|thumb|dnSpy being used to view the decompiled code of a mod's method in C#.]] '''Warning:''' in recent years, trojans have been released disguised as dnSpy, targetting security researchers. You should only download dnSpy from dnSpy's GitHub repository ([https://github.com/dnSpy/dnSpy/releases/latest dnSpy/dnSpy]). DnSpy is a .NET decompiler application that is designed to look visually similar to Visual Studio. It's popular with Rain World modders, modders of other .NET-based games, and security researchers. 32-bit and 64-bit Windows downloads can be found [https://github.com/dnSpy/dnSpy/releases/latest here]. dnSpy provides the most user convenience out of the options listed here, with handy usage analyzer and other inspection tools. It is, however, === ILSpy === ILSpy is a .NET decompiler backend. There are many frontends, often in the form of extensions for Visual Studio and Visual Studio Code. There's also a frontend built into JetBrains Rider. === ICsharpCode.Decompiler === Starting with version 2022, Visual Studio comes with its own decompiler: you can inspect classes from your reference libraries. == Writing Code == Most Rain World code modders use Visual Studio to write their code. This section will go over how to set up Visual Studio for Rain World modding. However, Visual Studio is limited to Windows, so you may find that Linux- and Mac-compatible options like [https://www.jetbrains.com/rider/ JetBrains Rider] and [https://code.visualstudio.com/ Visual Studio Code] are better suited to your use-case. === Installing Visual Studio === # Download the ''installer'' for latest version of VS [https://visualstudio.microsoft.com/downloads/ here]. Run it. # From the installer, create a new install of VS. In workload selection menu, make sure you have ".NET desktop development" selected. In Individual components, search for ".NET Framework 3.5 targeting pack" and enable it too. # Start the installation, wait for it to finish. [[File:CodeEnv-VSInstaller.png|none|thumb|alt=Visual Studio installer screen|Visual Studio installer screen]] === Creating a Visual Studio project === When creating a project for a rain world mod, you will need to a '''class library''' targeting '''.NET Framework 3.5'''. There are some problems you may encounter on this step. * Occasionally Visual Studio refuses to display targeting Framework 3.5 as an option. The pattern is unclear. * Creating a project targeting fw3.5 from Visual Studio's GUI causes it to be made with old <code>.csproj</code> file format (msbuild 2003), which restricts some features and is generally more messy. '''Steps to tell if the project is in older format''': ** Open the file in a text editor ** If it looks like a pile of piss-soaked spaghetti and has <code>Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"</code> around the beginning, it's old. Thus it's recommended to create project files from the command line with <code>dotnet new</code>: [[File:CodeEnv-DotnetCLI.png|none|thumb|alt=Creating a project with dotnet CLI|Creating a project with dotnet CLI]] Then open the resulting .csproj in Visual Studio, double click the project name in solution structure, and change the first block to have tags with following values: {| class="wikitable" |- ! Tag !! Value |- | TargetFramework || net35 |- | ImplicitUsings || disable |- | Nullable || disable |- | LangVersion || latest |} === Adding references === To compile mods and access the game code, you need to add some assemblies to your project as ''references''. To do this, you can * Use <code>Project -> Add project reference...</code> in VS. * Manually add <code>Include</code>s to your .csproj. For all mods, it is a good idea to reference: {|class="wikitable" |- ! Assembly !! Contains !! Notes |- | RainWorld_Data/Managed/AssemblyCSharp.dll || All of the vanilla game code || Use [https://github.com/Reinms/Stubber-Publicizer this tool] to remove accessibility restrictions |- | RainWorld_Data/Managed/UnityEngine.dll || Unity API methods |- | BepInEx/core/BepInEx.dll || [[BepInEx]] api |- | BepInEx/plugins/PartialityWrapper/HOOKS-Assembly-CSharp.dll || Hookgen events for methods in Assembly-CSharp for easily attaching code |- | BepInEx/core/MonoMod.RuntimeDetour || Classes and methods necessary for applying manual detours/hooks |- | BepInEx/core/MonoMod.Utils.dll || Classes and methods necessary for applying IL hooks, as well as some additional functionality |} Additionally, if you want to use a dependency mod, you will likely need to reference it too. If you are planning to share your code at some point, it is recommended that you set up your references without using absolute paths on your PC. This can be done in few ways: * Copying the reference files to a folder inside or near the project folder. * Setting up a folder symlink from somewhere in the project to a reference dir. On Windows, you can use [https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink mklink /J] from command prompt. In either case, you should [https://git-scm.com/docs/gitignore gitignore] references if they happen to be in a repo to avoid redistributing others' code. === Building === After you've wrote something, you will naturally want to run it and see if it works. As of now, there is no way of attaching a debugger to Rain World process, and version of Mono packed with the game does not load .pdb files. Thus you should always build your mods on Release configuration, even if you're mid-development. To load a mod into the game, you need to copy its assembly into respective BepInEx active folder (<code>BepInEx/plugins/</code> unless you are making an [[MonoMod Patches|mmpatch]]). You can automate this step by using a build event: * In Project properties view in VS, find Build Events, and into Post-build insert one of these: ** Unconditional build event with hardcoded destination: <code>copy /Y "$(TargetPath)" "Path/to/your/plugins/folder/here"</code> ** Copies files into a path defined by environment variable <code>RWMods</code> (if it exists): <code>if defined RWMods (copy /Y "$(TargetPath)" "%RWMods%")</code> By default, building a project copies most of its dependencies to the build destination (<code>bin/release/</code>). You can prevent it by selecting desired references in solution explorer, opening properties dock and setting <code>Copy Local</code> to <code>No</code>: [[File:CodeEnv-copyLocal.png|thumb|none|alt=Disabling Copy Local|Disabling Copy Local]] === Testing and Debugging === {{todo}} As mentioned, attaching a debugger to the game is currently not an option. This sections will contain several tips on mitigating the pain. * You can enable a separate console window for BepInEx output in <code>BepInEx/config/bepinex.cfg</code>. * From a [[BepInPlugins|BepInEx plugin]], use <code>Logger</code> property. If you need to lend access to your logger to different class, use something like: <syntaxhighlight lang="csharp"> public class MyPlugin : Baseunityplugin { public MyPlugin() { __me = new(this); } //using WeakReference to allow garbage collection private static WeakReference __me; public static MyPlugin ME => __me?.target as MyPlugin; //wrapper property. If you don't need a static member, just do this and pass plugin instance around. public ManualLogSource Logger_p => Logger; } //... MyPlugin.ME.Logger_p.Log(); </syntaxhighlight> * [https://github.com/casheww/RW-ToolBox/releases/latest This plugin] by casheww might help you with specific tasks == Misc tips and trivia == {{todo}} * You can use Embedded Resources to include arbitrary data, such as text files or images, with your assembly. To do this, select a file in Solution explorer, open Properties dock, and set <code>Build action</code> to <code>Embedded Resource</code>. You can retrieve the resources as <code>byte[]</code>s using methods '''GetManifestResourceNames''' and '''GetManifestResourceStream''' on <code>System.Reflection.Assembly</code> instance. [[Category:Code Mods]] 30d4c1c23a8ff82085e836e8eea4886c731caca6 228 227 2022-08-17T18:08:32Z Thalber 3 /* Reading Code */ wikitext text/x-wiki {{Cleanup}} == Reading Code == To mod Rain World, you need to be able to read the game's code. As it was written in C# and compiled against .NET Framework 3.5, you will need to use a decompiler to view the code. Remember that it is illegal to redistribute the game's code; decompiled copies are for your own use only. A few decompiler options are available to you, including: === dnSpy === [[File:dnspy.png|thumb|dnSpy being used to view the decompiled code of a mod's method in C#.]] '''Warning:''' in recent years, trojans have been released disguised as dnSpy, targetting security researchers. You should only download dnSpy from dnSpy's GitHub repository ([https://github.com/dnSpy/dnSpy/releases/latest dnSpy/dnSpy]). DnSpy is a .NET decompiler application that is designed to look visually similar to Visual Studio. It's popular with Rain World modders, modders of other .NET-based games, and security researchers. 32-bit and 64-bit Windows downloads can be found [https://github.com/dnSpy/dnSpy/releases/latest here]. dnSpy provides the most user convenience out of the options listed here, with handy usage analyzer and other inspection tools. It is, however, using an outdated version of decompiler backend, which causes it to choke and output invalid code in some cases (most notably, switch statements over strings). === ILSpy === ILSpy is a .NET decompiler backend. There are many frontends, often in the form of extensions for Visual Studio and Visual Studio Code. There's also a frontend built into JetBrains Rider. === ICsharpCode.Decompiler === Starting with version 2022, Visual Studio comes with its own decompiler: you can inspect classes from your reference libraries. == Writing Code == Most Rain World code modders use Visual Studio to write their code. This section will go over how to set up Visual Studio for Rain World modding. However, Visual Studio is limited to Windows, so you may find that Linux- and Mac-compatible options like [https://www.jetbrains.com/rider/ JetBrains Rider] and [https://code.visualstudio.com/ Visual Studio Code] are better suited to your use-case. === Installing Visual Studio === # Download the ''installer'' for latest version of VS [https://visualstudio.microsoft.com/downloads/ here]. Run it. # From the installer, create a new install of VS. In workload selection menu, make sure you have ".NET desktop development" selected. In Individual components, search for ".NET Framework 3.5 targeting pack" and enable it too. # Start the installation, wait for it to finish. [[File:CodeEnv-VSInstaller.png|none|thumb|alt=Visual Studio installer screen|Visual Studio installer screen]] === Creating a Visual Studio project === When creating a project for a rain world mod, you will need to a '''class library''' targeting '''.NET Framework 3.5'''. There are some problems you may encounter on this step. * Occasionally Visual Studio refuses to display targeting Framework 3.5 as an option. The pattern is unclear. * Creating a project targeting fw3.5 from Visual Studio's GUI causes it to be made with old <code>.csproj</code> file format (msbuild 2003), which restricts some features and is generally more messy. '''Steps to tell if the project is in older format''': ** Open the file in a text editor ** If it looks like a pile of piss-soaked spaghetti and has <code>Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"</code> around the beginning, it's old. Thus it's recommended to create project files from the command line with <code>dotnet new</code>: [[File:CodeEnv-DotnetCLI.png|none|thumb|alt=Creating a project with dotnet CLI|Creating a project with dotnet CLI]] Then open the resulting .csproj in Visual Studio, double click the project name in solution structure, and change the first block to have tags with following values: {| class="wikitable" |- ! Tag !! Value |- | TargetFramework || net35 |- | ImplicitUsings || disable |- | Nullable || disable |- | LangVersion || latest |} === Adding references === To compile mods and access the game code, you need to add some assemblies to your project as ''references''. To do this, you can * Use <code>Project -> Add project reference...</code> in VS. * Manually add <code>Include</code>s to your .csproj. For all mods, it is a good idea to reference: {|class="wikitable" |- ! Assembly !! Contains !! Notes |- | RainWorld_Data/Managed/AssemblyCSharp.dll || All of the vanilla game code || Use [https://github.com/Reinms/Stubber-Publicizer this tool] to remove accessibility restrictions |- | RainWorld_Data/Managed/UnityEngine.dll || Unity API methods |- | BepInEx/core/BepInEx.dll || [[BepInEx]] api |- | BepInEx/plugins/PartialityWrapper/HOOKS-Assembly-CSharp.dll || Hookgen events for methods in Assembly-CSharp for easily attaching code |- | BepInEx/core/MonoMod.RuntimeDetour || Classes and methods necessary for applying manual detours/hooks |- | BepInEx/core/MonoMod.Utils.dll || Classes and methods necessary for applying IL hooks, as well as some additional functionality |} Additionally, if you want to use a dependency mod, you will likely need to reference it too. If you are planning to share your code at some point, it is recommended that you set up your references without using absolute paths on your PC. This can be done in few ways: * Copying the reference files to a folder inside or near the project folder. * Setting up a folder symlink from somewhere in the project to a reference dir. On Windows, you can use [https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink mklink /J] from command prompt. In either case, you should [https://git-scm.com/docs/gitignore gitignore] references if they happen to be in a repo to avoid redistributing others' code. === Building === After you've wrote something, you will naturally want to run it and see if it works. As of now, there is no way of attaching a debugger to Rain World process, and version of Mono packed with the game does not load .pdb files. Thus you should always build your mods on Release configuration, even if you're mid-development. To load a mod into the game, you need to copy its assembly into respective BepInEx active folder (<code>BepInEx/plugins/</code> unless you are making an [[MonoMod Patches|mmpatch]]). You can automate this step by using a build event: * In Project properties view in VS, find Build Events, and into Post-build insert one of these: ** Unconditional build event with hardcoded destination: <code>copy /Y "$(TargetPath)" "Path/to/your/plugins/folder/here"</code> ** Copies files into a path defined by environment variable <code>RWMods</code> (if it exists): <code>if defined RWMods (copy /Y "$(TargetPath)" "%RWMods%")</code> By default, building a project copies most of its dependencies to the build destination (<code>bin/release/</code>). You can prevent it by selecting desired references in solution explorer, opening properties dock and setting <code>Copy Local</code> to <code>No</code>: [[File:CodeEnv-copyLocal.png|thumb|none|alt=Disabling Copy Local|Disabling Copy Local]] === Testing and Debugging === {{todo}} As mentioned, attaching a debugger to the game is currently not an option. This sections will contain several tips on mitigating the pain. * You can enable a separate console window for BepInEx output in <code>BepInEx/config/bepinex.cfg</code>. * From a [[BepInPlugins|BepInEx plugin]], use <code>Logger</code> property. If you need to lend access to your logger to different class, use something like: <syntaxhighlight lang="csharp"> public class MyPlugin : Baseunityplugin { public MyPlugin() { __me = new(this); } //using WeakReference to allow garbage collection private static WeakReference __me; public static MyPlugin ME => __me?.target as MyPlugin; //wrapper property. If you don't need a static member, just do this and pass plugin instance around. public ManualLogSource Logger_p => Logger; } //... MyPlugin.ME.Logger_p.Log(); </syntaxhighlight> * [https://github.com/casheww/RW-ToolBox/releases/latest This plugin] by casheww might help you with specific tasks == Misc tips and trivia == {{todo}} * You can use Embedded Resources to include arbitrary data, such as text files or images, with your assembly. To do this, select a file in Solution explorer, open Properties dock, and set <code>Build action</code> to <code>Embedded Resource</code>. You can retrieve the resources as <code>byte[]</code>s using methods '''GetManifestResourceNames''' and '''GetManifestResourceStream''' on <code>System.Reflection.Assembly</code> instance. [[Category:Code Mods]] 32ea6b4b47817f2075dc7bf2e6fe581cba6bebbb Category:Code Mods 14 74 206 123 2022-08-12T11:36:26Z Cashewww 2 added link to code env page wikitext text/x-wiki Code mods are incredibly versatile. They allow for fixing bugs in the vanilla game, adding quality of life (QoL) features, and all sorts of brand new features including new creatures and gamemodes. Code mods are sometimes included in Region Packs, either as supplimentary features or dependencies of those features. To load code mods, we use a modified version of [[BepInEx]]. == Writing Code Mods == Rain World is programmed in C# with Unity, meaning that we have access to plenty of .NET and Unity oriented modding tools. RW code mods are generally written in C# and built for the .NET Framework 3.5 runtime. If you're looking to start making code mods, it's recommended that you start with [[BepInPlugins]]. You're likely to get the most support with these, they're the easiest to make, and they're very capable. Before diving into the details of writing a code mod, you'll need to [[Code Environments|set up your code environment]]. Modern Rain World code mods typically come in a few flavours... * [[BepInPlugins]] - ''the most common. They largely use a technique called hooking, which allows for many possibilities and makes for good compatibility with other mods.'' * [https://docs.bepinex.dev/articles/dev_guide/preloader_patchers.html Preloader Patchers] - ''powered by Mono.Cecil. Used to apply changes to asseblies during the preloader phase.'' Older Rain World code mods are generally: * [[Standalone Mods]] * [[Partiality Mods]] * [[MonoMod Patches]] f1b87cb7f1001fafcc3fc7b7152c652e98ec0039 SlugBase 0 127 207 2022-08-15T16:45:56Z Cashewww 2 added slugbase page wikitext text/x-wiki SlugBase is a framework created by SlimeCubed for adding additional slugcat characters to Rain World, with an emphasis on compatibility. It allows modders to tweak their character's common stats and colours, and is useful for as a base for new characters that have unique abilities (which can be achieved using [[BepInPlugins|hooking]]). SlugBase can be downloaded from [https://github.com/SlimeCubed/SlugBase/releases/latest here]. SlugBase's documentation can be found [https://github.com/SlimeCubed/SlugBase/wiki here]. 65abecb221b3c588da3ac0041944f6a8e30fdd3a 208 207 2022-08-15T16:47:53Z Cashewww 2 added slugbase page to code cat wikitext text/x-wiki SlugBase is a framework created by SlimeCubed for adding additional slugcat characters to Rain World, with an emphasis on compatibility. It allows modders to tweak their character's common stats and colours, and is useful for as a base for new characters that have unique abilities (which can be achieved using [[BepInPlugins|hooking]]). SlugBase can be downloaded from [https://github.com/SlimeCubed/SlugBase/releases/latest here]. SlugBase's documentation can be found [https://github.com/SlimeCubed/SlugBase/wiki here]. [[Category:Code Mods]] 6574b9cb0cecb5539d80c5ab4b6f8d9d99d35844 212 208 2022-08-15T18:01:51Z Cashewww 2 added slugbase page to depencency cat wikitext text/x-wiki SlugBase is a framework created by SlimeCubed for adding additional slugcat characters to Rain World, with an emphasis on compatibility. It allows modders to tweak their character's common stats and colours, and is useful for as a base for new characters that have unique abilities (which can be achieved using [[BepInPlugins|hooking]]). SlugBase can be downloaded from [https://github.com/SlimeCubed/SlugBase/releases/latest here]. SlugBase's documentation can be found [https://github.com/SlimeCubed/SlugBase/wiki here]. [[Category:Code Mods]] [[Category:Dependencies]] c6f26342a26b59bb08b2bd352360a6b2d55f599b Warp 0 128 209 2022-08-15T17:36:14Z Cashewww 2 added warp page wikitext text/x-wiki Warp is a utility mod for Rain World that you can use to easily teleport to different rooms and regions. It is particularly useful for testing mods and [[CRS|region packs]]. Download and install Warp from [https://www.raindb.net/ RainDB] or [https://github.com/LeeMoriya/Warp/releases/latest Warp's GitHub page]. == Usage == Install Warp using [[BepInEx]], and then Warp menu will appear in the in-game pause menu. Clicking on a room button will teleport the player to the room's first entrance pipe (numbered 0). Clicking on a region button (other than the one the player is currently in) will load the region and show a list of its rooms instead. The loading process may take a few seconds if the region is particularly large. === Issues When Warping === If the region doesn't load then there is likely an issue with the region or room you are trying to warp to. Check your [[Logs|exceptionLog]] for errors and review any recent changes you made to the region/rooms. If you are making a custom region, make sure there are no errors with room connections in your World file, or problems with your room's geometry (e.g. invalid pipe entrances). If you have installed/uninstalled a new region, make sure you have started the game from a fresh save since that region was added or the game may freeze when switching regions or resting in a shelter. == Custom Den Position == Warp features and option to change which room the game considers as the player's den position (the room in which they start the next cycle). Note that if you're using [[Extended Dev Tools]], the 'Start Map' parameter in the <code>edtSetup.json</code> must be empty or it will override Warp. * Hold Shift and click a room name to set the den position. * Press C to reset the den position to its default. == Custom Regions Support == Warp supports [[CRS|Garrakx's Custom Regions Support]] mod which allows for easier creation of new regions and region changes, and will load new rooms from within your CustomResources folder. Below is how room lists are currently generated: === Current Region === The lust of rooms for the region you are currently in are taken directly from the list of loaded AbstractRooms. === Different Regions === When you click on a button for a different region, the room list is generated like so: # Rooms are added to the room list from the vanilla World folder. # Each Rooms folder found in CustomResources is scanned and rooms not already in the list are added. At the moment, this means that if a region pack is present in your CustomResources folder but has been manually disabled in its regionInfo.json, rooms from this folder will be regardless and clicking on them will do nothing. This is also technically the case for any region pack that removes rooms. [[Category:Utility Mods]] d73e03b3698c494a41635dd85acf444eba0f5b35 211 209 2022-08-15T17:53:06Z Cashewww 2 added warp menu image wikitext text/x-wiki Warp is a utility mod for Rain World that you can use to easily teleport to different rooms and regions. It is particularly useful for testing mods and [[CRS|region packs]]. Download and install Warp from [https://www.raindb.net/ RainDB] or [https://github.com/LeeMoriya/Warp/releases/latest Warp's GitHub page]. == Usage == [[File:WarpMenu.png|thumb|Region buttons are shown on the left, room buttons are shown on the right. There are also settings for different colour codings and order schemes. ]] Install Warp using [[BepInEx]], and then Warp menu will appear in the in-game pause menu. Clicking on a room button will teleport the player to the room's first entrance pipe (numbered 0). Clicking on a region button (other than the one the player is currently in) will load the region and show a list of its rooms instead. The loading process may take a few seconds if the region is particularly large. === Issues When Warping === If the region doesn't load then there is likely an issue with the region or room you are trying to warp to. Check your [[Logs|exceptionLog]] for errors and review any recent changes you made to the region/rooms. If you are making a custom region, make sure there are no errors with room connections in your World file, or problems with your room's geometry (e.g. invalid pipe entrances). If you have installed/uninstalled a new region, make sure you have started the game from a fresh save since that region was added or the game may freeze when switching regions or resting in a shelter. == Custom Den Position == Warp features and option to change which room the game considers as the player's den position (the room in which they start the next cycle). Note that if you're using [[Extended Dev Tools]], the 'Start Map' parameter in the <code>edtSetup.json</code> must be empty or it will override Warp. * Hold Shift and click a room name to set the den position. * Press C to reset the den position to its default. == Custom Regions Support == Warp supports [[CRS|Garrakx's Custom Regions Support]] mod which allows for easier creation of new regions and region changes, and will load new rooms from within your CustomResources folder. Below is how room lists are currently generated: === Current Region === The lust of rooms for the region you are currently in are taken directly from the list of loaded AbstractRooms. === Different Regions === When you click on a button for a different region, the room list is generated like so: # Rooms are added to the room list from the vanilla World folder. # Each Rooms folder found in CustomResources is scanned and rooms not already in the list are added. At the moment, this means that if a region pack is present in your CustomResources folder but has been manually disabled in its regionInfo.json, rooms from this folder will be regardless and clicking on them will do nothing. This is also technically the case for any region pack that removes rooms. [[Category:Utility Mods]] f2a5cecce447560fad6d56de2049539b78802b8d File:WarpMenu.png 6 129 210 2022-08-15T17:49:13Z Cashewww 2 wikitext text/x-wiki The Warp mod menu dc748564182acaf56856d1b32cafca87c485ce0a Category:Dev Tools 14 85 213 88 2022-08-15T18:06:25Z Cashewww 2 Cashewww moved page [[Category:Devtools]] to [[Category:Dev Tools]] wikitext text/x-wiki Pages desccribing function of in-game devools. e30fd404154b480d556931d3af8fafd14bd124d8 Category:Devtools 14 130 214 2022-08-15T18:06:25Z Cashewww 2 Cashewww moved page [[Category:Devtools]] to [[Category:Dev Tools]] wikitext text/x-wiki #REDIRECT [[:Category:Dev Tools]] f15a65a7511255792e35680d0c2311278a86ec4a Dev Tools 0 84 215 192 2022-08-15T18:07:12Z Cashewww 2 moved dev tools category wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ==Interface Tabs== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. <tabber> |-| Room settings= This tab mostly contains settings for base room visuals, such as palette, cloud cover and terrain wetness. === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === [[File:Fadepalette example.png]] ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image on the right shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! {|class="wikitable" |- ! '''Effect''' !! '''Description''' |- | SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. |- | SkyBloom || Increases how fuzzy/bloomy the sky's light is. |- | LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. |- | Bloom || Similar to SkyBloom, but applies to lights. |- | Fog || Creates a white cloudy effect at layer 1. Not compatible with |- | Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- |- | GreenSparks || Underhang, and the Legs' green sparkles. |- | VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | Flies || Spawns small flys that buzz around the room and land on objects. |- | FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | TinyDragonFly || Spawns tiny bugs that fly around plants. |- | RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | Ant || Spawns small jumping bugs. |- | Beetle || Spawns small beetles that slowly fly around the room. |- | WaterGlowWorm || Spawns small worms that swim around in water. |- | Wasp || Spawns small wasps that quickly dart between walls. |- | Moth || Spawns small white moths which slowly flutter around the room. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom`, VoidMelt </syntaxhighlight> |-| Objects= Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds= [[File:soundTab.png|400px|right|border|]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map= {{todo|target=tab}} [[File:mapTab.png|400px|right|border|]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections.png|400px|right|border|Connections on dev map]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png|400px|right|border|Canon view of the map]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png|400px|right|border|Example of a rendered map .png file]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers= {{todo|target=tab}} [[File:triggerTab.png|600px|right|border|Trigger tab view]] <span id="general-controls"></span> == General controls == === Save === Saves the current effects and room settings to a file inside the region’s World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by pressing R and returning to the room to see the changes. === Inherent from template === Will set the values stored in a specific template the region has to this room. === Save as template: === Saves the current room’s settings as a template for easy re-use. == Triggers Menu == '''Triggers''' are the mechanism in which some in-game events occur, such as specific songs playing, projections being displayed by the player guide overseer, or information text being displayed at the bottom of the screen. Clicking one of the four options in the bottom right-hand box will place a trigger of that type, which can be moved just like other devtools objects. === Trigger Options === Triggers have a number of settings which determine what the trigger does and under what circumstances. {| class="wikitable" |+ |- ! Trigger setting !! Description |- | Active from cycle || The minimum total cycle requirement for the trigger to activate. |- | Active up to cycle || The maximum cycle limit for the trigger to activate - if the player has a cycle count higher than this number, the trigger will not activate. |- | Fire chance || A random percentage chance for the trigger to activate, from 0% to 100%. |- | Trigger delay || How many seconds between the requirements for the trigger being met and the event occurring. |- | Karma req || The minimum karma the player needs for the trigger to activate (from 0 to 5) |- | Can only fire once/Can fire multiple times || Self-explanatory, determines whether the trigger only fires once or not. |- | No entrance requirement/Entrance XX || Determines whether the player can enter from any entrance pipe, or whether they need to come through a specific one. When an entrance is selected, a red line will connect this entrance and the options box. |- | White, Yellow, Red || Determines which gamemodes the trigger fires on - Survivor, Hunter or Monk. A gamemode’s name being displayed means that the trigger will fire in said gamemode. |} === Event Types === The lowest button on the options box lets you pick what type of event you want to add. ==== MusicEvent ==== Plays a song from the soundtrack. * The first button lets you pick the song you want to play. Files for these songs can be found in *Rain World, or many of them can be found [https://www.youtube.com/playlist?list=PLPJWSVeszYFBo1oAXYgzGfJfewnGKgGna online.] {| class="wikitable" |+ MusicEvent options |- ! Option !! Description |- | Play volume || The volume the song plays at. |- | Fade in || In seconds, how long the song takes to reach full volume. |- | Song priority || If this song’s priority is higher than another’s, then this song will continue to play if the other trigger is activated. If the priority is lower, then the higher one will play instead of it. |- | Drone volume || WIP, presumably adds a background drone sound at the set volume. |- | Fade out at threat || The threat level at which the song fades out and is overtaken by the threat music. |- | Rest cycles || If this trigger can activate multiple times, the number of cycles for the trigger to wait before being able to fire again. |- | Room transitions || How many rooms the song will continue playing through. |- | One song per cycle || Whether or not the same song can activate multiple times in one cycle. |- | Play once/loop || Determines whether the song plays once or loops |- | Continue at death || Continue playing the song when the player dies. |- | Continue through gate || Continue playing the song when the player uses a region gate. |} ==== StopMusicEvent ==== As the name says, stops one or more MusicEvents. The first button lets you pick the song you want to stop/exclude. * '''Priority:''' If a song has a higher priority than the trigger, it won’t stop. * '''Fade out:''' Same as fade in, but fading out to silence. * '''Stop all songs/stop specific song/stop all but specific song:''' Self-explanatory, song selected at the top of the box is what this refers to. ==== '''PoleMimicSubtleReveal''' ==== Causes a pole mimic to flutter slightly when activated. ==== '''ShowProjectedImageEvent''' ==== Shows player guide overseer projections ==== '''RoomSpecificTextMessage''' ==== Causes specific text prompt to appear. Prompts are hardcoded by room name {{Cn}} ==== '''BringPlayerGuideToRoom''' ==== Forces player overseer to current room === Trigger Types === * '''Spot:''' The most commonly used trigger; activates when slugcat walks into a specific circular area of the room. This is indicated by a white area-of-effect which can be moved and scaled. * '''SeeCreature:''' ''WIP, presumably activates upon a certain creature being seen.'' * '''RegionBump:''' Activates either when the region is entered or at the beginning of a cycle where the region name and cycle count is shown. * '''PreRegionBump:''' Seemingly functions the same way as RegionBump. </tabber> <div> [[Category:Dev Tools]] b51ff494b3d10a025ccb7687441d1812f1cdb7ad Main Page 0 1 216 109 2022-08-15T18:09:46Z Cashewww 2 added messy quick links wikitext text/x-wiki __NOTOC__ [[File:RWModdingTitle.png|800px|frameless|center]] <br> <div id="intro-text" style="text-align: center;"> '''Welcome!''' The Rain World Modding Wiki is a place to share information about modding the video game, ''Rain World''. For more about the game, check out the '''[https://rainworld.miraheze.org/wiki/Rain_World_Wiki Official Rain World Wiki]'''! This wiki is currently in the process of being ported from an old wiki. To get involved, be sure to check out the modding category in the [https://discord.gg/rainworld Rain World Discord]. </div> == Where to Start... == For instructions for installing mods, see [[Installing Mods]]. On a technical level, mods can be split into the following families: * [[:Category:Code Mods|Code Mods]] (any mod where the main component is a .dll file) * [[:Category:Content Mods|Content Mods]] (this includes region packs, arenas, etc.). Follow one of the links above to learn more about making these kinds of mods. Sometimes there is overlap. For example a [[Custom Region Support|region pack]] (a type of content mod) may require additional code mods for custom creatures, or a code mod may require additional asset files (though often they are embedded within the dll). If you have questions that the wiki can't yet answer, feel free to ask in the modding category in the [https://discord.gg/rainworld Rain World Discord]. If you have modding knowledge that the wiki doesn't yet have, please do contribute! === Quick Links === * [[:Category:Code Mods]] * [[:Category:Content Mods]] * [[:Category:Dev Tools]] * [[:Category:Dependencies]] * [[:Category:Utility Mods]] * [[CRS]] * [[Warp]] 590991ee726b636181c096d7bd401133f12f3305 217 216 2022-08-15T18:10:05Z Cashewww 2 /* Quick Links */ wikitext text/x-wiki __NOTOC__ [[File:RWModdingTitle.png|800px|frameless|center]] <br> <div id="intro-text" style="text-align: center;"> '''Welcome!''' The Rain World Modding Wiki is a place to share information about modding the video game, ''Rain World''. For more about the game, check out the '''[https://rainworld.miraheze.org/wiki/Rain_World_Wiki Official Rain World Wiki]'''! This wiki is currently in the process of being ported from an old wiki. To get involved, be sure to check out the modding category in the [https://discord.gg/rainworld Rain World Discord]. </div> == Where to Start... == For instructions for installing mods, see [[Installing Mods]]. On a technical level, mods can be split into the following families: * [[:Category:Code Mods|Code Mods]] (any mod where the main component is a .dll file) * [[:Category:Content Mods|Content Mods]] (this includes region packs, arenas, etc.). Follow one of the links above to learn more about making these kinds of mods. Sometimes there is overlap. For example a [[Custom Region Support|region pack]] (a type of content mod) may require additional code mods for custom creatures, or a code mod may require additional asset files (though often they are embedded within the dll). If you have questions that the wiki can't yet answer, feel free to ask in the modding category in the [https://discord.gg/rainworld Rain World Discord]. If you have modding knowledge that the wiki doesn't yet have, please do contribute! == Quick Links == * [[:Category:Code Mods]] * [[:Category:Content Mods]] * [[:Category:Dev Tools]] * [[:Category:Dependencies]] * [[:Category:Utility Mods]] * [[CRS]] * [[Warp]] 96d39a529698fc71a9a826c6297c49478b56b2e9 220 217 2022-08-16T08:03:50Z Thalber 3 /* Where to Start... */ wikitext text/x-wiki __NOTOC__ [[File:RWModdingTitle.png|800px|frameless|center]] <br> <div id="intro-text" style="text-align: center;"> '''Welcome!''' The Rain World Modding Wiki is a place to share information about modding the video game, ''Rain World''. For more about the game, check out the '''[https://rainworld.miraheze.org/wiki/Rain_World_Wiki Official Rain World Wiki]'''! This wiki is currently in the process of being ported from an old wiki. To get involved, be sure to check out the modding category in the [https://discord.gg/rainworld Rain World Discord]. </div> == Where to Start... == For instructions for installing mods, see [[Installing Mods]]. On a technical level, mods can be split into the following families: * [[:Category:Code Mods|Code Mods]] (any mod where the main component is a .dll file) * [[:Category:Content Mods|Content Mods]] (this includes region packs, arenas, etc.). Follow one of the links above to learn more about making these kinds of mods. Sometimes there is overlap. For example a [[Custom Region Support|region pack]] (a type of content mod) may require additional code mods for custom creatures, or a code mod may require additional asset files (though often they are embedded within the dll). If you have questions that the wiki can't yet answer, feel free to ask in the modding category in the [https://discord.gg/rainworld Rain World Discord]. == Contributing == If you have modding knowledge that the wiki doesn't yet have, please do contribute! The following categories contain pages demanding attention: * [[:Category:Cleanup needed]] * [[:Category:Unfinished]] == Quick Links == * [[:Category:Code Mods]] * [[:Category:Content Mods]] * [[:Category:Dev Tools]] * [[:Category:Dependencies]] * [[:Category:Utility Mods]] * [[CRS]] * [[Warp]] b7ccfdb3ad8b7479bf66aa5413dc99112c6fecaf Category:Utilities and Tools 14 131 218 2022-08-15T18:11:18Z Cashewww 2 Created page with "This category is for mods that are good tools for further mod development but aren't a dependencies." wikitext text/x-wiki This category is for mods that are good tools for further mod development but aren't a dependencies. abac0f0f1bef32efeb25cd71e8bbcc232c371d21 File:CodeEnv-DotnetCLI.png 6 132 222 2022-08-17T16:05:19Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:CodeEnv-VSInstaller.png 6 133 223 2022-08-17T16:05:38Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:CodeEnv-copyLocal.png 6 134 229 2022-08-17T18:11:31Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 ConfigMachine 0 115 230 186 2022-08-17T18:30:52Z Thalber 3 /* Writing Translation txt */ replaced corrupted text wikitext text/x-wiki {{Cleanup}} '''Configmachine''' is a dependency mod that allows other mods to easily create in-game config GUI. It's currently shipped with [[BepInEx]] installation. == Features == === OptionInterface === This is the most common method of adding config screen to your mod. ==== Registering ==== '''OptionalUI.OptionInterface''' is the base class for option interfaces. <syntaxhighlight lang="csharp"> public class MyOI : OptionInterface { public MyOI() : base (plugin: MyPlugin.instance) // Your BaseUnityPlugin instance. Examples assume you have a static singleton instance of your mod. { } } </syntaxhighlight> Now add <code>LoadOI</code> static method in your <code>BaseUnityPlugin</code> class that returns your OptionInterface. <syntaxhighlight lang="c#"> public static OptionInterface LoadOI() => return new MyOI(); //set return type to "object" if you want your mod to be loaded even if CM is not. In that case, you will need to handle CM's absence on your own. </syntaxhighlight> ==== Designing GUI ==== For designing your GUI, using [https://inkscape.org/ Inkscape] is strongly suggested. With Inkscape, create a file with 600 x 600 pixel resolution, then enable [View] - [Canvas Orientation] - [Flip Vertically]. (Alternatively, you can use any CAD program which has up and right as positive axis by default) <!--The image below is a diagram of <code>Colorfoot</code>’s first <code>OpTab</code>.--> [[File:Colorfoot-GUI.png|thumb|right|alt=Colorfoot's GUI as an example|Colorfoot's GUI as an example]] All UIelements have bottom-left <code>pos</code>ition and rectangular <code>size</code>. (Some have <code>fixedSize</code> which you can see from the summary of their constructors). Think every element like rectangles, and arrange them as you need. (Circular UIelements have <code>rad</code> instead; You can consider them as a square with 2 * rad for its dimensions) [[File:Colorfoot-GUI0.png|thumb|none|alt=Example GUI Positioning|Example GUI Positioning]] For <code>pos</code> parameters, use the relative coordinate from bottom-left from the canvas to your item. For <code>size</code> parameters, use their size in pixel. If you’re using Inkscape with [Flip Vertically] setting on, you can get those from their properties without any calculation. [[File:Colorfoot-Inkscape.png|thumb|none|alt=Example GUI Inkscape|Example GUI in Inkscape]] Here are some tips for designing GUI: * If you have many things to display, organise them with categories and use <code>OpRect</code> to surround them. * You don’t have to put everything in a single <code>OpTab</code>. If the canvas gets crowded, disperse your items for easier readability. * Try to avoid using smaller <code>OpScrollBox</code>s to store many things in one place even if that’s an option: The users cannot see everything in a single screen which reduces usability greatly. ==== Initialization ==== <code>OptionInterface.Initialize</code> is called in IntroRoll(for loading configuration) and ConfigMenu (for displaying to users). You can check whether Initialize is called in ConfigMenu or not with <code>OptionInterface.isOptionMenu</code>. It usually goes like this following example: <syntaxhighlight lang="csharp"> public override void Initialize() { base.Initialize(); // This should be called before everything else Tabs = new OpTab[2]; // you can have up to 20 tabs Tabs[0] = new OpTab("Main"); // Each OpTab is 600 x 600 pixel sized canvas Tabs[1] = new OpTab("Second") { color = Color.cyan }; // You can change its button and canvas colour too // After Initializing Tabs, create UIelements and add them to tabs } </syntaxhighlight> Now initialize <code>UIelement</code>s and add them to <code>OpTab</code> (or <code>OpScrollBox</code>). The Z-order (the order in which they’re drawn) of <code>UIelement</code>s is the order of constructors, ''not'' the order they’re added to <code>OpTab</code>. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpLabel(100f, 500f, "My Text") { description = "This is My Text" }); // Any UIelement can have description, which will be shown // at the bottom of the screen when the mouse cursor is over it </syntaxhighlight> <code>UIconfig</code>s are a subcategory of <code>UIelement</code> which have <code>key</code> and <code>value</code> for storing user input values, both of them get saved automatically by Config Machine. Their constructor accepts <code>key</code> and <code>defaultValue</code> on top of everything else. <code>key</code> must be unique for all elements in your OI unless they are cosmetic. Setting the key to empty or anything that starts with <code>_</code> (underbar) will turn it <code>cosmetic</code>, and the value won’t be saved. Cosmetic UIconfig is useful when you want to have provided <code>UIconfig</code> for UI purpose but not for an actual configurable. (Similarly, ModID that starts with <code>_</code> will be completely ignored by Config Machine) <syntaxhighlight lang="csharp"> OpCheckBox chkExample = new OpCheckBox(260f, 360f, "Example", true); Tabs[0].AddItems(chkExample, new OpLabel(260f, 390f, "Enable Example") { bumpBehav = chkExample.bumpBehav }); // BumpBehaviour is Config Machine's custom class that allows smoothly animated reaction with the input // Setting OpLabel's bumpBehav to other UIconfig/UItrigger's bumpBehav allows it to highlight with that element </syntaxhighlight> <code>UItrigger</code>s are the other subcategory of <code>UIelement</code>s which have <code>signal</code>s. When the user activates an <code>UItrigger</code> in some way, it will call the <code>Signal</code> function in OptionInterface which will be explained later. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpSimpleButton(new Vector2(400f, 200f), new Vector2(100f, 24f), "press", "Press Me")); </syntaxhighlight> ==== Update ==== <code>Update</code> function is called every frame when the game is in ConfigMenu, and this OptionInterface is currently active (The user has currently selected this mod from the list on left). This is useful to make reactive GUI, especially since each <code>UIconfig</code> instance can have only one value saved. The following example code uses cosmetic <code>OpRadioButtonGroup</code> to have four <code>OpColorPicker</code>s in a single spot. <syntaxhighlight lang="csharp"> private OpRadioButtonGroup rbgSelect; private int select; private OpColorPicker[] cpkPlayers; public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; select = 0; rbgSelect = new OpRadioButtonGroup("_", select); Tabs[0].AddItems(rbgSelect); rbgSelect.SetButtons(new OpRadioButton[] { new OpRadioButton(50f, 100f){ description = "The Survivor"}, new OpRadioButton(100f, 100f){ description = "The Monk"}, new OpRadioButton(150f, 100f){ description = "The Hunter"}, new OpRadioButton(200f, 100f){ description = "The Nightcat"} } ); OpColorPicker[] cpkPlayers = new OpColorPicker[4]; for (int i = 0; i < 4; i++) { Tabs[0].AddItems(new OpLabel(50f * i, 70f, rbgSelect.buttons[i].description) { bumpBehav = rbgSelect.buttons[i].bumpBehav }); cpkPlayers[i] = new OpColorPicker(new Vector2(100f, 300f), $"Color{i}", "FFFFFF"); cpkPlayers[i].Hide(); } cpkPlayers[select].Show(); Tabs[0].AddItems(cpkPlayers); } public override void Update(float dt) { base.Update(dt); // dt is deltaTime if (select != rbgSelect.valueInt) { for (int i = 0; i < cpkPlayers.Length; i++) { cpkPlayers[i].Hide(); } select = rbgSelect.valueInt; cpkPlayers[select].Show(); } } </syntaxhighlight> ==== ConfigOnChange ==== <code>ConfigOnChange</code> is called whenever <code>config</code> Dictionary is updated, mainly when Config Machine loads OptionInterfaces in IntroRoll, and when the user saves changes of configuration in ConfigMenu. Override this method to grab your configurable values. <code>config</code> Dictionary is where <code>UIconfig</code>’s value is stored. The following is an example of how to convert a string value to the corresponding type. <syntaxhighlight lang="csharp">public override void ConfigOnChange() { base.ConfigOnChange(); MyMod.config.myInt = int.Parse(config["keyInt"]); MyMod.config.myFloat = float.Parse(config["keyFloat"]); MyMod.config.myKey = OpKeyBinder.StringToKeyCode(config["keyKey"]); MyMod.config.myColor = OpColorPicker.HexToColor(config["keyColor"]); } </syntaxhighlight> ==== Signal ==== <code>Signal</code> is called when the user has interacted with <code>UItrigger</code>. Override this to have your OI to react. <syntaxhighlight lang="csharp"> public override void Signal(UItrigger trigger, string signal) { switch (signal) { case "reset": ConfigMenu.ResetCurrentConfig(); // This is the same as pressing Reset Config Button. break; } } </syntaxhighlight> === Generated OIs === <code>GeneratedOI</code> is a child class of <code>OptionInterface</code> that helps generating fixed-format GUI with less effort. <span id="displaying-basic-profile"></span> ==== Displaying Basic Profile ==== Simply inheriting <code>GeneratedOI</code> instead of <code>OptionInterface</code> works. This does make your mod dependent to Config Machine, and Config Machine generates GUI to display the basic information of your mod without this dependency. So this is only useful when you’re using OptionInterface for other features, like its Translation API. <syntaxhighlight lang="c#"> public class MyOI : GeneratedOI { private const string desc = "Changes this thing and that thing"; public MyOI() : base(plugin: MyPlugin.instance, desc) { transFile = "MyPlugin.Translation.txt"; } } </syntaxhighlight> The code above would generate a GUI like the following image: [[File:GeneratedOI-sample.png|thumb|none|alt=GeneratedOI Sample|GeneratedOI Sample]] You can also use its static method <code>AddBasicProfile</code> for basic profiles on top of the canvas. This also has an overload that accepts <code>OpScrollBox</code> instead of <code>OpTab</code>, if you have <code>OpScrollBox</code> replacing <code>OpTab</code>. <syntaxhighlight lang="c#"> public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; GeneratedOI.AddBasicProfile(Tabs[0], rwMod); Tabs[0].AddItems(new OpCheckBox(100f, 350f, "EnableStuff", false) { description = "Enables this stuff" }); } </syntaxhighlight> ==== BepInEx.Configuration ==== If you don't provide an OptionInterface, BepInEx can generate a simple config screen from your [[BepInPlugins|plugin]]'s config bindings (see <code>BepInEx.Configuration</code>). If this happens, CM will not create a separate file to store your config values. This method has upsides and downsides. * You don’t need to reference Config Machine in your project, and this doesn’t create a dependency for Config Machine. * The users can configure the plugin by opening the cfg file in Notepad outside the game. * However, you do not have control on detailed GUI design. First, we need <code>ConfigEntry</code> which you can bind to the <code>Config</code> property of <code>BaseUnityPlugin</code>. Consult [https://docs.bepinex.dev/articles/dev_guide/plugin_tutorial/4_configuration.html BepInEx Documentation] for farther detail. <syntaxhighlight lang="c#"> public static ConfigEntry<string> cfgText; public static ConfigEntry<bool> cfgCheck; void Awake() { cfgText = Config.Bind( "General", // section: defines which OpTab this will go "My Setting", // key: the name of setting "Hello, world!" // defaultValue "This is a description. It does things." // The description will be shown the right side of UIconfig // When you hover your mouse on UIconfig, // the first sentence will be displayed at the bottom of the screen ); cfgCheck = Config.Bind("General", "My Other Setting", true, "Another description is this."); } </syntaxhighlight> To access those settings, use <code>Value</code>. <syntaxhighlight lang="c#"> if (cfgCheck.Value) { Logger.LogMessage(cfgText.Value); } </syntaxhighlight> === Translation Support === While you can support translation for your mod on your own, Config Machine also offers translation solution. ==== Preparation ==== <code>OptionInterface</code> has a method called <code>Translate</code>, and when it's initially called, it will load specified (<code>transFile</code>) txt file from your assembly and make Dictionary depending on Rain World's language setting. In <code>BaseUnityPlugin.LoadOI</code> method, store the <code>OptionInterface</code> instance in somewhere before returning it. <syntaxhighlight lang="c#"> public static MyOI oi; public static MyOI LoadOI() { oi = new MyOI(); return oi; } </syntaxhighlight> Then make a static method that calls the translation method. <syntaxhighlight lang="c#">public static string Translate(string orig) { if (oi != null) { return oi.Translate(orig); } return orig; } </syntaxhighlight> Now when you need to translate something, you can pass your string through this method. ==== Writing Translation txt ==== Create a txt file that contains translation, too. Add txt file to your project, ''make sure'' that its encoding is <code>UTF-8</code>, then set it to be [Embedded Resources] for its compile setting. Then, in the constructor of your OptionInterface, set <code>transFile</code> to that resource name. If you have not put it in any folder, it's usually <code>&lt;ProjectName&gt;.&lt;TxtFileName&gt;.txt</code>, but you might get it wrong. If it's wrong when <code>OptionInterface.Translate</code> is initially called, Config Machine will log all the resources in your assembly in exceptionLog.txt so you can copy from it. <syntaxhighlight lang="c#"> public MyOI() : base(plugin: MyPlugin.instance) { this.transFile = "MyPlugin.Translation.txt"; // if you do not know the resource name, just call Translate. // ConfigMachine will log all the resources in your assembly in exceptionLog.txt. } </syntaxhighlight> The format of the translation txt file for Config Machine is quite primitive. First, you add a keyword, then <code>|</code> for language separator, then language ID (<code>eng, ita, ger, spa, por, kor, jap, rus)</code>), <code>$</code> for another separator, then translation. If there is no translation, the translator will return the keyword, unless there is a translation for <code>eng</code>. (In that case, English "translation" will be used as default translation) The following is formatting example for txt file. <!-- corrupted korean samples have been replaced with russian, sorry folks ~~~~ --> <pre> // If the first two characters are '//', this line will be ignored. Nightcat Horn Colour|rus$Цвет рога // If you have variables, avoid using partial sentences. Not every language has the same subject-verb-object order. Press &lt;ThrowKey&gt; to stab.|rus$Нажмите &lt;ThrowKey&gt; для атаки. // When translating the shorter-phrase, the translation might be sensitive with context, but English one does not. Duplicate key causes error(You can check exceptionLog.txt for duplicates), so you can set 'eng' translation for these cases. Property_as of possession|eng$Property|rus$Собственность Property_as of quality|eng$Property|rus$Свойство // For line-breaks, use \n. (In code, it'd be \\n) Each line represents a phrase, so you can't use actual line-break in a single chunk. LINE\nBREAK|rus$ПЕРЕНОС\nСТРОКИ</pre> ==== Running Translation ==== And here are some examples in code. Yes, running every text through the <code>Translate</code> method is tedious, but this is usually how it's done in Rain World or many other games. Make sure to check your mod in another language to confirm you haven’t missed any item. <syntaxhighlight lang="c#"> labelCpkrRadio.text = MyPlugin.Translate("Nightcat Horn Colour"); instance.room.game.cameras[0].hud.textPrompt.AddMessage(MyPlugin.Translate("Press <ThrowKey> to stab.").Replace("<ThrowKey>", k.ToString())); // k is variable in this example. labelLineBreak.text = MyPlugin.Translate("LINE\\nBREAK"); </syntaxhighlight> <!-- These aren't the part of tutorial but more of tips. This does not just apply for making Rain World mods but to general, whenever you're making something that supports translation. * When you have variables in your sentence, do not use partial phrases and Frankenstein it later with <code>string.Concat</code>. Not every language has the same grammar order of subject-verb-object as English. * Leave credits to the translators, since you¡¯re most likely getting volunteers from them. This is both good for showing gratitude to the translators and keeping the quality of the translation. The lack of credits equals a lack of responsibility. * Do not use machine translation. That usually hurts the user experience rather than enhancing it. --> == Acceptable Types == As of Config Machine <code>v1.5.1</code>, it accepts the following types and uses provided UIconfig. (Height is the pixel height that how much this ConfigEntry would use. And each entry get 20 pixeled gaps in between) {|class="wikitable" !align="right" width="23%"| type !align="center" width="29%"| UIconfig !align="right" width="23%"| Height !width="23%"| Note |- |align="right"| bool |align="center"| OpCheckBox |align="right"| 60 | |- |align="right"| byte |align="center"| OpSliderSubtle |align="right"| 90 | Range: [0, 20] |- |align="right"| uint |align="center"| OpSlider |align="right"| 90 | Range: [0, 100] |- |align="right"| int |align="center"| OpTextBox |align="right"| 60 | Accepts: Int |- |align="right"| float |align="center"| OpTextBox |align="right"| 60 | Accepts: Float |- |align="right"| string(Hex) |align="center"| OpColorPicker |align="right"| 170 | When defaultValue is Hex |- |align="right"| string |align="center"| OpTextBox |align="right"| 60 | When defaultValue is not Hex; Accepts: ASCII |- |align="right"| KeyCode |align="center"| OpKeyBinder |align="right"| 100 | |- |align="right"| enumType |align="center"| OpResourceSelector |align="right"| 60 | |- |align="right"| default |align="center"| N/A |align="right"| | Will warn the user that this plugin has ConfigEntry that’s not supported by Config Machine |} == Available UI Elements == Full list of available UI elements can be found [[ConfigMachine/Provided Elements|here]]. [[Category:Dependencies]] [[Category:Code Mods]] 1719d8ccf033001af9384174636aedc32fa3719b 231 230 2022-08-17T18:31:26Z Thalber 3 /* Writing Translation txt */ wikitext text/x-wiki {{Cleanup}} '''Configmachine''' is a dependency mod that allows other mods to easily create in-game config GUI. It's currently shipped with [[BepInEx]] installation. == Features == === OptionInterface === This is the most common method of adding config screen to your mod. ==== Registering ==== '''OptionalUI.OptionInterface''' is the base class for option interfaces. <syntaxhighlight lang="csharp"> public class MyOI : OptionInterface { public MyOI() : base (plugin: MyPlugin.instance) // Your BaseUnityPlugin instance. Examples assume you have a static singleton instance of your mod. { } } </syntaxhighlight> Now add <code>LoadOI</code> static method in your <code>BaseUnityPlugin</code> class that returns your OptionInterface. <syntaxhighlight lang="c#"> public static OptionInterface LoadOI() => return new MyOI(); //set return type to "object" if you want your mod to be loaded even if CM is not. In that case, you will need to handle CM's absence on your own. </syntaxhighlight> ==== Designing GUI ==== For designing your GUI, using [https://inkscape.org/ Inkscape] is strongly suggested. With Inkscape, create a file with 600 x 600 pixel resolution, then enable [View] - [Canvas Orientation] - [Flip Vertically]. (Alternatively, you can use any CAD program which has up and right as positive axis by default) <!--The image below is a diagram of <code>Colorfoot</code>’s first <code>OpTab</code>.--> [[File:Colorfoot-GUI.png|thumb|right|alt=Colorfoot's GUI as an example|Colorfoot's GUI as an example]] All UIelements have bottom-left <code>pos</code>ition and rectangular <code>size</code>. (Some have <code>fixedSize</code> which you can see from the summary of their constructors). Think every element like rectangles, and arrange them as you need. (Circular UIelements have <code>rad</code> instead; You can consider them as a square with 2 * rad for its dimensions) [[File:Colorfoot-GUI0.png|thumb|none|alt=Example GUI Positioning|Example GUI Positioning]] For <code>pos</code> parameters, use the relative coordinate from bottom-left from the canvas to your item. For <code>size</code> parameters, use their size in pixel. If you’re using Inkscape with [Flip Vertically] setting on, you can get those from their properties without any calculation. [[File:Colorfoot-Inkscape.png|thumb|none|alt=Example GUI Inkscape|Example GUI in Inkscape]] Here are some tips for designing GUI: * If you have many things to display, organise them with categories and use <code>OpRect</code> to surround them. * You don’t have to put everything in a single <code>OpTab</code>. If the canvas gets crowded, disperse your items for easier readability. * Try to avoid using smaller <code>OpScrollBox</code>s to store many things in one place even if that’s an option: The users cannot see everything in a single screen which reduces usability greatly. ==== Initialization ==== <code>OptionInterface.Initialize</code> is called in IntroRoll(for loading configuration) and ConfigMenu (for displaying to users). You can check whether Initialize is called in ConfigMenu or not with <code>OptionInterface.isOptionMenu</code>. It usually goes like this following example: <syntaxhighlight lang="csharp"> public override void Initialize() { base.Initialize(); // This should be called before everything else Tabs = new OpTab[2]; // you can have up to 20 tabs Tabs[0] = new OpTab("Main"); // Each OpTab is 600 x 600 pixel sized canvas Tabs[1] = new OpTab("Second") { color = Color.cyan }; // You can change its button and canvas colour too // After Initializing Tabs, create UIelements and add them to tabs } </syntaxhighlight> Now initialize <code>UIelement</code>s and add them to <code>OpTab</code> (or <code>OpScrollBox</code>). The Z-order (the order in which they’re drawn) of <code>UIelement</code>s is the order of constructors, ''not'' the order they’re added to <code>OpTab</code>. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpLabel(100f, 500f, "My Text") { description = "This is My Text" }); // Any UIelement can have description, which will be shown // at the bottom of the screen when the mouse cursor is over it </syntaxhighlight> <code>UIconfig</code>s are a subcategory of <code>UIelement</code> which have <code>key</code> and <code>value</code> for storing user input values, both of them get saved automatically by Config Machine. Their constructor accepts <code>key</code> and <code>defaultValue</code> on top of everything else. <code>key</code> must be unique for all elements in your OI unless they are cosmetic. Setting the key to empty or anything that starts with <code>_</code> (underbar) will turn it <code>cosmetic</code>, and the value won’t be saved. Cosmetic UIconfig is useful when you want to have provided <code>UIconfig</code> for UI purpose but not for an actual configurable. (Similarly, ModID that starts with <code>_</code> will be completely ignored by Config Machine) <syntaxhighlight lang="csharp"> OpCheckBox chkExample = new OpCheckBox(260f, 360f, "Example", true); Tabs[0].AddItems(chkExample, new OpLabel(260f, 390f, "Enable Example") { bumpBehav = chkExample.bumpBehav }); // BumpBehaviour is Config Machine's custom class that allows smoothly animated reaction with the input // Setting OpLabel's bumpBehav to other UIconfig/UItrigger's bumpBehav allows it to highlight with that element </syntaxhighlight> <code>UItrigger</code>s are the other subcategory of <code>UIelement</code>s which have <code>signal</code>s. When the user activates an <code>UItrigger</code> in some way, it will call the <code>Signal</code> function in OptionInterface which will be explained later. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpSimpleButton(new Vector2(400f, 200f), new Vector2(100f, 24f), "press", "Press Me")); </syntaxhighlight> ==== Update ==== <code>Update</code> function is called every frame when the game is in ConfigMenu, and this OptionInterface is currently active (The user has currently selected this mod from the list on left). This is useful to make reactive GUI, especially since each <code>UIconfig</code> instance can have only one value saved. The following example code uses cosmetic <code>OpRadioButtonGroup</code> to have four <code>OpColorPicker</code>s in a single spot. <syntaxhighlight lang="csharp"> private OpRadioButtonGroup rbgSelect; private int select; private OpColorPicker[] cpkPlayers; public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; select = 0; rbgSelect = new OpRadioButtonGroup("_", select); Tabs[0].AddItems(rbgSelect); rbgSelect.SetButtons(new OpRadioButton[] { new OpRadioButton(50f, 100f){ description = "The Survivor"}, new OpRadioButton(100f, 100f){ description = "The Monk"}, new OpRadioButton(150f, 100f){ description = "The Hunter"}, new OpRadioButton(200f, 100f){ description = "The Nightcat"} } ); OpColorPicker[] cpkPlayers = new OpColorPicker[4]; for (int i = 0; i < 4; i++) { Tabs[0].AddItems(new OpLabel(50f * i, 70f, rbgSelect.buttons[i].description) { bumpBehav = rbgSelect.buttons[i].bumpBehav }); cpkPlayers[i] = new OpColorPicker(new Vector2(100f, 300f), $"Color{i}", "FFFFFF"); cpkPlayers[i].Hide(); } cpkPlayers[select].Show(); Tabs[0].AddItems(cpkPlayers); } public override void Update(float dt) { base.Update(dt); // dt is deltaTime if (select != rbgSelect.valueInt) { for (int i = 0; i < cpkPlayers.Length; i++) { cpkPlayers[i].Hide(); } select = rbgSelect.valueInt; cpkPlayers[select].Show(); } } </syntaxhighlight> ==== ConfigOnChange ==== <code>ConfigOnChange</code> is called whenever <code>config</code> Dictionary is updated, mainly when Config Machine loads OptionInterfaces in IntroRoll, and when the user saves changes of configuration in ConfigMenu. Override this method to grab your configurable values. <code>config</code> Dictionary is where <code>UIconfig</code>’s value is stored. The following is an example of how to convert a string value to the corresponding type. <syntaxhighlight lang="csharp">public override void ConfigOnChange() { base.ConfigOnChange(); MyMod.config.myInt = int.Parse(config["keyInt"]); MyMod.config.myFloat = float.Parse(config["keyFloat"]); MyMod.config.myKey = OpKeyBinder.StringToKeyCode(config["keyKey"]); MyMod.config.myColor = OpColorPicker.HexToColor(config["keyColor"]); } </syntaxhighlight> ==== Signal ==== <code>Signal</code> is called when the user has interacted with <code>UItrigger</code>. Override this to have your OI to react. <syntaxhighlight lang="csharp"> public override void Signal(UItrigger trigger, string signal) { switch (signal) { case "reset": ConfigMenu.ResetCurrentConfig(); // This is the same as pressing Reset Config Button. break; } } </syntaxhighlight> === Generated OIs === <code>GeneratedOI</code> is a child class of <code>OptionInterface</code> that helps generating fixed-format GUI with less effort. <span id="displaying-basic-profile"></span> ==== Displaying Basic Profile ==== Simply inheriting <code>GeneratedOI</code> instead of <code>OptionInterface</code> works. This does make your mod dependent to Config Machine, and Config Machine generates GUI to display the basic information of your mod without this dependency. So this is only useful when you’re using OptionInterface for other features, like its Translation API. <syntaxhighlight lang="c#"> public class MyOI : GeneratedOI { private const string desc = "Changes this thing and that thing"; public MyOI() : base(plugin: MyPlugin.instance, desc) { transFile = "MyPlugin.Translation.txt"; } } </syntaxhighlight> The code above would generate a GUI like the following image: [[File:GeneratedOI-sample.png|thumb|none|alt=GeneratedOI Sample|GeneratedOI Sample]] You can also use its static method <code>AddBasicProfile</code> for basic profiles on top of the canvas. This also has an overload that accepts <code>OpScrollBox</code> instead of <code>OpTab</code>, if you have <code>OpScrollBox</code> replacing <code>OpTab</code>. <syntaxhighlight lang="c#"> public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; GeneratedOI.AddBasicProfile(Tabs[0], rwMod); Tabs[0].AddItems(new OpCheckBox(100f, 350f, "EnableStuff", false) { description = "Enables this stuff" }); } </syntaxhighlight> ==== BepInEx.Configuration ==== If you don't provide an OptionInterface, BepInEx can generate a simple config screen from your [[BepInPlugins|plugin]]'s config bindings (see <code>BepInEx.Configuration</code>). If this happens, CM will not create a separate file to store your config values. This method has upsides and downsides. * You don’t need to reference Config Machine in your project, and this doesn’t create a dependency for Config Machine. * The users can configure the plugin by opening the cfg file in Notepad outside the game. * However, you do not have control on detailed GUI design. First, we need <code>ConfigEntry</code> which you can bind to the <code>Config</code> property of <code>BaseUnityPlugin</code>. Consult [https://docs.bepinex.dev/articles/dev_guide/plugin_tutorial/4_configuration.html BepInEx Documentation] for farther detail. <syntaxhighlight lang="c#"> public static ConfigEntry<string> cfgText; public static ConfigEntry<bool> cfgCheck; void Awake() { cfgText = Config.Bind( "General", // section: defines which OpTab this will go "My Setting", // key: the name of setting "Hello, world!" // defaultValue "This is a description. It does things." // The description will be shown the right side of UIconfig // When you hover your mouse on UIconfig, // the first sentence will be displayed at the bottom of the screen ); cfgCheck = Config.Bind("General", "My Other Setting", true, "Another description is this."); } </syntaxhighlight> To access those settings, use <code>Value</code>. <syntaxhighlight lang="c#"> if (cfgCheck.Value) { Logger.LogMessage(cfgText.Value); } </syntaxhighlight> === Translation Support === While you can support translation for your mod on your own, Config Machine also offers translation solution. ==== Preparation ==== <code>OptionInterface</code> has a method called <code>Translate</code>, and when it's initially called, it will load specified (<code>transFile</code>) txt file from your assembly and make Dictionary depending on Rain World's language setting. In <code>BaseUnityPlugin.LoadOI</code> method, store the <code>OptionInterface</code> instance in somewhere before returning it. <syntaxhighlight lang="c#"> public static MyOI oi; public static MyOI LoadOI() { oi = new MyOI(); return oi; } </syntaxhighlight> Then make a static method that calls the translation method. <syntaxhighlight lang="c#">public static string Translate(string orig) { if (oi != null) { return oi.Translate(orig); } return orig; } </syntaxhighlight> Now when you need to translate something, you can pass your string through this method. ==== Writing Translation txt ==== Create a txt file that contains translation, too. Add txt file to your project, ''make sure'' that its encoding is <code>UTF-8</code>, then set it to be [Embedded Resources] for its compile setting. Then, in the constructor of your OptionInterface, set <code>transFile</code> to that resource name. If you have not put it in any folder, it's usually <code>&lt;ProjectName&gt;.&lt;TxtFileName&gt;.txt</code>, but you might get it wrong. If it's wrong when <code>OptionInterface.Translate</code> is initially called, Config Machine will log all the resources in your assembly in exceptionLog.txt so you can copy from it. <syntaxhighlight lang="c#"> public MyOI() : base(plugin: MyPlugin.instance) { this.transFile = "MyPlugin.Translation.txt"; // if you do not know the resource name, just call Translate. // ConfigMachine will log all the resources in your assembly in exceptionLog.txt. } </syntaxhighlight> The format of the translation txt file for Config Machine is quite primitive. First, you add a keyword, then <code>|</code> for language separator, then language ID (<code>eng, ita, ger, spa, por, kor, jap, rus)</code>), <code>$</code> for another separator, then translation. If there is no translation, the translator will return the keyword, unless there is a translation for <code>eng</code>. (In that case, English "translation" will be used as default translation) The following is formatting example for txt file. <!-- corrupted korean samples have been replaced with russian, sorry folks ~~thalber --> <pre> // If the first two characters are '//', this line will be ignored. Nightcat Horn Colour|rus$Цвет рога // If you have variables, avoid using partial sentences. Not every language has the same subject-verb-object order. Press &lt;ThrowKey&gt; to stab.|rus$Нажмите &lt;ThrowKey&gt; для атаки. // When translating the shorter-phrase, the translation might be sensitive with context, but English one does not. Duplicate key causes error(You can check exceptionLog.txt for duplicates), so you can set 'eng' translation for these cases. Property_as of possession|eng$Property|rus$Собственность Property_as of quality|eng$Property|rus$Свойство // For line-breaks, use \n. (In code, it'd be \\n) Each line represents a phrase, so you can't use actual line-break in a single chunk. LINE\nBREAK|rus$ПЕРЕНОС\nСТРОКИ</pre> ==== Running Translation ==== And here are some examples in code. Yes, running every text through the <code>Translate</code> method is tedious, but this is usually how it's done in Rain World or many other games. Make sure to check your mod in another language to confirm you haven’t missed any item. <syntaxhighlight lang="c#"> labelCpkrRadio.text = MyPlugin.Translate("Nightcat Horn Colour"); instance.room.game.cameras[0].hud.textPrompt.AddMessage(MyPlugin.Translate("Press <ThrowKey> to stab.").Replace("<ThrowKey>", k.ToString())); // k is variable in this example. labelLineBreak.text = MyPlugin.Translate("LINE\\nBREAK"); </syntaxhighlight> <!-- These aren't the part of tutorial but more of tips. This does not just apply for making Rain World mods but to general, whenever you're making something that supports translation. * When you have variables in your sentence, do not use partial phrases and Frankenstein it later with <code>string.Concat</code>. Not every language has the same grammar order of subject-verb-object as English. * Leave credits to the translators, since you¡¯re most likely getting volunteers from them. This is both good for showing gratitude to the translators and keeping the quality of the translation. The lack of credits equals a lack of responsibility. * Do not use machine translation. That usually hurts the user experience rather than enhancing it. --> == Acceptable Types == As of Config Machine <code>v1.5.1</code>, it accepts the following types and uses provided UIconfig. (Height is the pixel height that how much this ConfigEntry would use. And each entry get 20 pixeled gaps in between) {|class="wikitable" !align="right" width="23%"| type !align="center" width="29%"| UIconfig !align="right" width="23%"| Height !width="23%"| Note |- |align="right"| bool |align="center"| OpCheckBox |align="right"| 60 | |- |align="right"| byte |align="center"| OpSliderSubtle |align="right"| 90 | Range: [0, 20] |- |align="right"| uint |align="center"| OpSlider |align="right"| 90 | Range: [0, 100] |- |align="right"| int |align="center"| OpTextBox |align="right"| 60 | Accepts: Int |- |align="right"| float |align="center"| OpTextBox |align="right"| 60 | Accepts: Float |- |align="right"| string(Hex) |align="center"| OpColorPicker |align="right"| 170 | When defaultValue is Hex |- |align="right"| string |align="center"| OpTextBox |align="right"| 60 | When defaultValue is not Hex; Accepts: ASCII |- |align="right"| KeyCode |align="center"| OpKeyBinder |align="right"| 100 | |- |align="right"| enumType |align="center"| OpResourceSelector |align="right"| 60 | |- |align="right"| default |align="center"| N/A |align="right"| | Will warn the user that this plugin has ConfigEntry that’s not supported by Config Machine |} == Available UI Elements == Full list of available UI elements can be found [[ConfigMachine/Provided Elements|here]]. [[Category:Dependencies]] [[Category:Code Mods]] b4df2bd402b68d8144599e833309299fd1f7fa8a Partiality 0 99 232 133 2022-08-17T18:45:57Z Thalber 3 Protected "[[Partiality]]": We don't have more to say about Partiality ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite)) wikitext text/x-wiki '''Important''' - Partiality is abandoned. Instead, you should use [[BepInEx]]. <br/> Partiality loader was the primary mod loader used for Rain World modding for some years. Partiality loader is no longer maintained, so the mod loader of choice for Rain World is now [[BepInEx]]. The versions of BepInEx used by the Rain World modding community support the usage of Partiality mods. The authority for Rain World Partiality mods is [https://drive.google.com/file/d/1eZE6EVwslhnSIFffmoUxDgUCRTAvD-zP/view Topicular’s Guide to Partiality Modding]. While some aspects are a out of date, many of the concepts relating to the game’s code still apply and are very useful. BepInEx plugins / BepInPlugins are an alternative for Partiality hook mods. For more info, see the [[BepInPlugins]] page. [[Category:Code Mods]] 79a5e04f5e7df016aca441b72510b075685f22a0 The Architecture of Rain World 0 135 233 2022-08-17T21:07:57Z Henpemaz 12 Tips on inspecting Rain World rooms and documentation on some of its designs wikitext text/x-wiki == Preamble == So you want to make "a region", maybe "the region", and chances are you want to take some inspiration from the game itself instead of creating something completely alien and unrelated. It helps to know that Rain World was made alongside the very tools that made it. Rooms like the ones from Outskirts and the ones in the Wall were made with very different versions of the Level Editor and very different tilesets available. Matching the look for each region involves checking out how it was made, since there's no generic "Rain World" recipe. == Inspecting existing rooms == In order to mimic a room style, you'll have to look closely at the source material. Two important steps here are: * Open the room in-game, or browse it at the [https://henpemaz.github.io/Rain-World-Interactive-Map/map.html?region=SU&room=SU_B04 interactive map] to look at its details. * Open the room project for the room in the level editor. That's right! All the vanilla room projects ship with the editor, and you can learn lots from them. In the Level Editor, when inspecting existing rooms, a few important things to notice are: * You can "sample" a tile in the Tile Editor, by hovering over it and pressing "Q". That will select the tile that is placed under your cursor, so you can easily identify it and see which tab it is on. * You can see placed effects and where they're applied in the Effect Editor by entering "Edit" mode ("E") and then using W and S to browse through the placed effects. * You can sample placed props in the Props Editor by pressing "B" With these resources, you can know in fine detail how that particular room was made, and you can use that and adapt it to your needs. == Documented Designs == Note: This guide was migrated and adapted from the previous wiki, the section about shelters was removed. This article is a collection of guides dedicated on explaining how to get certain structures seen all throughout Rain World "just right." Anything from tips and tricks, to guides of how to make complex multi-tile machines. These guides are not limited to just vanilla Rain World, and any other unique and helpful structures are welcome to be added! === Sky Islands Data Boxes === Flashing blinking lights surrounded by kinked tubes and machines are used in a few isolated rooms in sky islands. ==== Basic Construction: ==== A large rectangle of "SuperStructure" material. With ZeroG tube props between it and the nearest walls. Can optionally be covered by machines or cement, and then washed over with slime effect to make it slightly more rough and broken down. In game, a "superStructureFuses" object needs to be placed and aligned with the holes on the material to properly display the blinking lights inside the machine. Various objects and machine can be placed around it to extend the object from being a simple blinking box, into some strange machine. The rooms palette and cloud cover helps to hide the simplicity of the actual construction. === The Wall - General Style Guide === NOTICE - The Wall is a very complex and multilayered area. Experience with the editor is heavily recommended! The wall's construction is a mix of large detail tiles from "The Wall" category. Cooling rods are assembled out of their component pieces, usually in order of large rod segments with one or two tip segments before their cap. However oddly ordered rods can spice up the look. Rods often have poles sticking out from their caps. The bases of cooling rods are always present in single or pairs. These rods are connected directly to the wall using three "Giant screw" tiles from the "machines" category, and then connected to giant pipes traveling into the wall. The Wall itself is constructed of cement, and dense pipes. Using huge pipes and other segments of the wall as spacers. The base of cooling rods can also attach to larger dome machines. These often have multiple segments of "under cooler" beneath them. If you need to pass between a cooling rod and the wall itself. The two segments are separated by three giant screws on each side. With huge pipes between them. Poles are used to climb between the gaps. Short cut entrances are very often wedged between wall segments, or directly attached to the tops of domes or pipes. Short cuts almost never come out from cooling rods themselves, but from the larger structures behind them. Cooling rods along the side of the wall are used as floors and ceilings to rooms. However the Wall's cooling rods never extend for more then room in width. The only segments of the wall that stick out from the wall itself are large spherical chambers with antennas on them. These will be done in a separate architecture guide. The far background of the Wall consists of thick pipes, cement, and rarely a "very large beam" from the "metal" category. The tips of these beams can be capped off with "pillar beam connection"s from the "underhang" category. The wall's materials are broken up into two segments. Certain areas having large chunks of "random machines" fitted with pipes. The tunnels through the machines using "crawlspace" tiles on top of them. Other tunnels outside of the machines use "crawlhole" tiles. The upper sections are dotted with "Asian sign" tiles. Usually mixed between dense pipes or scaffolding. These can be used to break up the color of the palette and make your walls seem less uniform. Huge chains are used as props to beak up the background itself. These are anchored to beams and the Wall's side by small blocks of "random machine" material. Plant life along the wall is very scarce. Mostly being various grasses and hanging roots. The rubble effect is also used here to create a more varied ground. However, using piles of large trash or dirt can also work to break up the straight lines that the cooling rods and domes create. Grasses often grow out of these. Food is also rare on the wall. Very few segments having hanging fruits. Slime and BlackGoo effects as always help to break up the more straight and dull segments of bare materials. The underside of cooling rods are slimier then the tops. Hanging chains can also be used to help break up the background. Just be sure none of the chains connect off the edge of the screen! Finally. The "AboveCloudsView" room setting in the dev tools is used to draw the giant sea of clouds view near the upper half of the wall. This however, requires your room to be at a certain height above 0 in the Map Tab's "canon view." An easy method to configure this is to simply drag the first room you want this effect to appear in upwards on the map. Save, and reload the room by dying. If the effect is not far enough up the wall yet, keep going. If it is too far, move it back down until you are happy with its elevation, and then build your map off of this room's elevation. The default palette of the wall is 19, with a very slight fade to 29. EffectA is 8 and effectB is 7. A heavy fog, a light bloom, wind sounds with the wall's own unique humming sound effects complete most of the region's ambience. Don't be afraid to explore some stranger twists to the region's structure however! 647da7c74aaa89d93dc771688bead653e34a0cd7 234 233 2022-08-18T05:33:12Z Thalber 3 wikitext text/x-wiki {{Cleanup}} == Preamble == So you want to make "a region", maybe "the region", and chances are you want to take some inspiration from the game itself instead of creating something completely alien and unrelated. It helps to know that Rain World was made alongside the very tools that made it. Rooms like the ones from Outskirts and the ones in the Wall were made with very different versions of the Level Editor and very different tilesets available. Matching the look for each region involves checking out how it was made, since there's no generic "Rain World" recipe. == Inspecting existing rooms == In order to mimic a room style, you'll have to look closely at the source material. Two important steps here are: * Open the room in-game, or browse it at the [https://henpemaz.github.io/Rain-World-Interactive-Map/map.html?region=SU&room=SU_B04 interactive map] to look at its details. * Open the room project for the room in the level editor. That's right! All the vanilla room projects ship with the editor, and you can learn lots from them. In the Level Editor, when inspecting existing rooms, a few important things to notice are: * You can "sample" a tile in the Tile Editor, by hovering over it and pressing "Q". That will select the tile that is placed under your cursor, so you can easily identify it and see which tab it is on. * You can see placed effects and where they're applied in the Effect Editor by entering "Edit" mode ("E") and then using W and S to browse through the placed effects. * You can sample placed props in the Props Editor by pressing "B" With these resources, you can know in fine detail how that particular room was made, and you can use that and adapt it to your needs. == Documented Designs == Note: This guide was migrated and adapted from the previous wiki, the section about shelters was removed. This article is a collection of guides dedicated on explaining how to get certain structures seen all throughout Rain World "just right." Anything from tips and tricks, to guides of how to make complex multi-tile machines. These guides are not limited to just vanilla Rain World, and any other unique and helpful structures are welcome to be added! === Sky Islands Data Boxes === Flashing blinking lights surrounded by kinked tubes and machines are used in a few isolated rooms in sky islands. ==== Basic Construction: ==== A large rectangle of "SuperStructure" material. With ZeroG tube props between it and the nearest walls. Can optionally be covered by machines or cement, and then washed over with slime effect to make it slightly more rough and broken down. In game, a "superStructureFuses" object needs to be placed and aligned with the holes on the material to properly display the blinking lights inside the machine. Various objects and machine can be placed around it to extend the object from being a simple blinking box, into some strange machine. The rooms palette and cloud cover helps to hide the simplicity of the actual construction. === The Wall - General Style Guide === NOTICE - The Wall is a very complex and multilayered area. Experience with the editor is heavily recommended! The wall's construction is a mix of large detail tiles from "The Wall" category. Cooling rods are assembled out of their component pieces, usually in order of large rod segments with one or two tip segments before their cap. However oddly ordered rods can spice up the look. Rods often have poles sticking out from their caps. The bases of cooling rods are always present in single or pairs. These rods are connected directly to the wall using three "Giant screw" tiles from the "machines" category, and then connected to giant pipes traveling into the wall. The Wall itself is constructed of cement, and dense pipes. Using huge pipes and other segments of the wall as spacers. The base of cooling rods can also attach to larger dome machines. These often have multiple segments of "under cooler" beneath them. If you need to pass between a cooling rod and the wall itself. The two segments are separated by three giant screws on each side. With huge pipes between them. Poles are used to climb between the gaps. Short cut entrances are very often wedged between wall segments, or directly attached to the tops of domes or pipes. Short cuts almost never come out from cooling rods themselves, but from the larger structures behind them. Cooling rods along the side of the wall are used as floors and ceilings to rooms. However the Wall's cooling rods never extend for more then room in width. The only segments of the wall that stick out from the wall itself are large spherical chambers with antennas on them. These will be done in a separate architecture guide. The far background of the Wall consists of thick pipes, cement, and rarely a "very large beam" from the "metal" category. The tips of these beams can be capped off with "pillar beam connection"s from the "underhang" category. The wall's materials are broken up into two segments. Certain areas having large chunks of "random machines" fitted with pipes. The tunnels through the machines using "crawlspace" tiles on top of them. Other tunnels outside of the machines use "crawlhole" tiles. The upper sections are dotted with "Asian sign" tiles. Usually mixed between dense pipes or scaffolding. These can be used to break up the color of the palette and make your walls seem less uniform. Huge chains are used as props to beak up the background itself. These are anchored to beams and the Wall's side by small blocks of "random machine" material. Plant life along the wall is very scarce. Mostly being various grasses and hanging roots. The rubble effect is also used here to create a more varied ground. However, using piles of large trash or dirt can also work to break up the straight lines that the cooling rods and domes create. Grasses often grow out of these. Food is also rare on the wall. Very few segments having hanging fruits. Slime and BlackGoo effects as always help to break up the more straight and dull segments of bare materials. The underside of cooling rods are slimier then the tops. Hanging chains can also be used to help break up the background. Just be sure none of the chains connect off the edge of the screen! Finally. The "AboveCloudsView" room setting in the dev tools is used to draw the giant sea of clouds view near the upper half of the wall. This however, requires your room to be at a certain height above 0 in the Map Tab's "canon view." An easy method to configure this is to simply drag the first room you want this effect to appear in upwards on the map. Save, and reload the room by dying. If the effect is not far enough up the wall yet, keep going. If it is too far, move it back down until you are happy with its elevation, and then build your map off of this room's elevation. The default palette of the wall is 19, with a very slight fade to 29. EffectA is 8 and effectB is 7. A heavy fog, a light bloom, wind sounds with the wall's own unique humming sound effects complete most of the region's ambience. Don't be afraid to explore some stranger twists to the region's structure however! 2e548339785bed976940c08c6d3818b16410fa25 World File Format 0 114 235 173 2022-08-18T06:07:25Z Thalber 3 Thalber moved page [[World file format]] to [[World File Format]] without leaving a redirect wikitext text/x-wiki {{Cleanup}} [[File:regionFormat.png|thumb|right|alt=regionFormat|regionFormat]] This page describes worldfile format for RW regions. The world_XX.txt file is present in every region Rain World loads, and determines various room settings such as their pipe connections, the spawns of enemies, and specific flags like shelters and gates. NOTE: Creature spawns for the region are generated when you first enter it on a save. Changing room connections or creature spawns in WORLD_XX after that corrupts save data. '''Reset your saveslot or revert your save to before you entered to avoid bugs'''. == Comments == Worldfile format supports comments: if a line starts with double slash (<code>//</code>), it is ignored entirely. == Room Connections == Room connections section is bounded by <code>ROOMS</code> and <code>END ROOMS</code> tags. These control which pipe entrance leads to what room, and vice versa. Unique room flags that specify certain attributes about the room (such as if it is a shelter or a gate room) are set here as well. The format is as follows: <syntaxhighlight lang="">ROOM : door0, door1, door2, etc : FLAG </syntaxhighlight> === Examples === A standard room with two room-connecting pipes. These will form the bulk of your region. <syntaxhighlight lang="">TR_T07 : TR_T01, TR_P02 </syntaxhighlight> A standard room, with five doors. However, pipes 1, 2 and 3 have no connection. Each pipe inside a room has a specific number starting from 0. These can be viewed using the [[Dev Tools]]' map tab, or by entering the room with dev tools enabled and pressing M. <syntaxhighlight lang="">TR_W19 : TR_L05, DISCONNECTED, DISCONNECTED, DISCONNECTED, TR_W18 </syntaxhighlight> A shelter. These rooms will often be copied from other regions when you are first learning how to make a region. All vanilla save rooms have a single door. <syntaxhighlight lang="">TR_S01 : TR_P01 : SHELTER </syntaxhighlight> A region gate. Doors on the other side of the gate are set to DISCONNECTED. They will automatically be shown as connected doors at runtime. If you need to show a save room door specifically on the other side of the gate, you can use the ExitSymbolShelter object, in the dev tool’s object tab to change the door symbols as required. <syntaxhighlight lang="">GATE_SS_TR : DISCONNECTED, TR_L07 : GATE </syntaxhighlight> A swarm room allows batflies to spawn in the room, as long as the map contains bat nests. If the room has bat nests but is not marked as a swarm room, those nests will always be inactive. The dev tools map tab provides the options needed to control where they will migrate and rooms they will avoid. <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> A scavenger outpost. Use in conjunction with ScavengerOutpost placedObject to create a scavenger toll. <syntaxhighlight lang="">SU_C02 : SU_A45, SU_A07 : SCAVOUTPOST </syntaxhighlight> === Understanding door connections === [[File:regionFormatConnection.png|thumb|none|alt=regionFormatConnection|regionFormatConnection]] For a door to be properly connected, both ends must point to each other using valid doors. For this example, both rooms will have two doors. Door0 will be on the left, and door1 on the right. Door indices are decided specifically for your room, so be sure to check in game how your doors have been assigned by the [[Level Editor]]. The DT Map tab can also be used to see the links between doors. As in the picture to the right. Properly connected doors will show both lines pointing to the set door on the other end. Doors with incorrect links will point off to the bottom right <!--(A disconnected door will also do this,)--> <!--do fucking what--> and a door connected to another room, but that room has no door back (or lacks enough doors!) will point to the center of the room on the map tab page. <syntaxhighlight lang=""> RG_ROOM1 : DISCONNECTED, RG_ROOM2 </syntaxhighlight> <syntaxhighlight lang=""> RG_ROOM2: RG_ROOM1 </syntaxhighlight> Room1 will have its right hand door connected to Room2. Because of this, we need to use DISCONNECTED as a placeholder for its left hand door, door0. Then set door1 to connect to Room2 Room2 will connect to Room1 using door0. Due to this, we do not need to define the right hand door. It will assume it to be disconnected. === Room Tags === Room tags assign certain properties to rooms depending on what the tag is. Tags are assigned like <syntaxhighlight lang=""> [ROOM] : [CONNECTIONS] : [TAG] </syntaxhighlight> Example: <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> {|class="wikitable" !width="18%"| '''<u>Tag</u>''' !width="81%"| '''<u>Function</u>''' |- | SHELTER | Makes the room a shelter. When there are multiple pipes in the room: the animated door is placed at the bottom right most pipe. |- | GATE | Makes the room a gate. Entrances on the other side of the gate are set to DISCONNECTED, and are shown automatically to be connected. |- | SWARMROOM | Allows batflies to be spawned from batfly hives. |- | PERF_HEAVY | Causes the room to be abstractized quicker when player is not inside, can reduce offscreen performance toll of very large rooms. |- | SCAVOUTPOST | Makes the room into a scavenger outpost. Scavs will spawn here and only let you pass if you have a pearl. The exact outpost location is set by the “ScavengerOutpost” devtools object. |- | SCAVTRADER | Spawns a scavenger merchant into the room. Will trade items with you. The merchant is controlled by the “TradeOutpost” devtools object. |} === Important quirks to rooms and doors === When setting up your region, be sure that you always use your region’s prefix to help each room have a unique name. If not, Rain World will treat repeated names as being other rooms, and even re-use rooms from other region folders entirely. If you don’t use your region prefix, changes made with devtools can also wind up getting saved to unexpected places. To avoid these problems, always prefix your room with its region code, and give them unique names. Multiple pipes in a room may all go to the same room. However, these will all act like a single pipe, and you will not be able to set the specific destination pipes. There are no cases in vanilla Rain World where multiple pipes in the current room lead to the same next room. They will all lead to separate rooms. For example, if you had four pipes leading from one room to another. you would need to create a minimum of three unique rooms for each of the other pipes to act as an interconnection. == Creature Spawns == Creature spawn data section is bounded by <code>CREATURES</code> and <code>END CREATURES</code> tags. Rain World only creates creature spawns when you enter a region for the first time on a save<!--, or after an excessive number of cycles has passed--><!--never heard of it before, may be bogus ~thalber-->. {|class="wikitable" !align="center" width="12%"| '''Lizards''' !align="center" width="25%"| '''Insects''' !align="center" width="13%"| '''Amphibians''' !align="center" width="18%"| '''Flying''' !align="center" width="16%"| '''Plants''' !align="center" width="12%"| '''Other''' |- |align="center"| Pink |align="center"| Spider |align="center"| Salamander |align="center"| CicadaA |align="center"| PoleMimic, Mimic* |align="center"| Scavenger |- |align="center"| Green |align="center"| Small Centipede |align="center"| Leech |align="center"| CicadaB |align="center"| Tentacle, TentaclePlant* |align="center"| Lantern Mouse, Mouse* |- |align="center"| Blue |align="center"| Centipede, Centi, Cent* |align="center"| SeaLeech |align="center"| Vulture |align="center"| |align="center"| Worm, Garbage Worm* |- |align="center"| Yellow |align="center"| Red Centipede, RedCenti, RedCentipede* |align="center"| JetFish, Jetfish* |align="center"| KingVulture, King Vulture* |align="center"| |align="center"| Miros, MirosBird* |- |align="center"| White |align="center"| DropBug, Dropbug, DropWig, Dropwig* |align="center"| Snail |align="center"| Needle, Needle Worm* |align="center"| |align="center"| Tube, TubeWorm* |- |align="center"| Black |align="center"| BigSpider |align="center"| Lev, Leviathan |align="center"| SmallNeedleWorm |align="center"| |align="center"| Bro, BroLongLegs* |- |align="center"| Cyan |align="center"| SpitterSpider |align="center"| |align="center"| Cicada** |align="center"| |align="center"| Daddy, DaddyLongLegs* |- |align="center"| Red |align="center"| EggBug, Eggbug* |align="center"| |align="center"| |align="center"| |align="center"| |} (*) Interchangeable names (**) Switches between CicadaA and CicadaB) <syntaxhighlight lang=""> //Creature spawns can be specific to a certain character. (0, 1) makes something appear for monk and survivor, (2) only for hunter (character filter)ROOM : PipeNumber-Creature-{optional flags}-Count </syntaxhighlight> === Examples === A single green lizard, spawning from pipe 2, on all difficulties. <syntaxhighlight lang=""> SU_A10 : 2-Green </syntaxhighlight> A single red lizard, spawning from pipe 3, on Hunter only. <syntaxhighlight lang=""> (2)SU_A10 : 3-Red </syntaxhighlight> A hoard of 5 yellow lizards spawning from pipe 1, on Monk only. <syntaxhighlight lang=""> (1)SU_A10 : 1-Yellow-5 </syntaxhighlight> A Daddy longlegs spawning from pipe 4, but only on easy and normal difficulties. <syntaxhighlight lang=""> (0,1)SU_A10 : 4-Daddy </syntaxhighlight> A very angry white lizard that spawns from pipe 3, on all difficulties. the “Mean” flag can be set from 0 to 1, and will change the enemy’s personality to pursue you aggressively depending on how high it is set. <syntaxhighlight lang=""> SU_A10 : 3-White-{Mean:0.9} </syntaxhighlight> Some enemies require a unique room known as OFFSCREEN. These enemies use special doors that are automatically added to your level to move between rooms. These include vultures, scavengers, leviathans, and miros birds. This example spawns two off screen vultures. <syntaxhighlight lang=""> OFFSCREEN : 0-Vulture-2 </syntaxhighlight> Enemy flags still apply to offscreen enemies. This will spawn a very aggressive KingVulture that will rarely leave the screen if it spots slugcat, but only on Hunter. <syntaxhighlight lang=""> (2)OFFSCREEN : 0-KingVulture-{Mean:1} </syntaxhighlight> <span id="important-quirks-to-creatures"></span> === Important quirks === Enemies may be set to spawn from the same nest pipes. However, do not be surprised if they somehow kill each other offscreen very quickly if you do this. A daddy long legs may have no problems consuming an entire hoard of yellow lizards for example. Enemies will often drag you back to their home nest pipes, but may also choose other pipes they like, even in different rooms. During the end of a cycle, almost every enemy will rush to a nearby nest, if they spawned from it or not. Many creatures that would not intuitively appear to nest in pipes, likely does so, you just never reach them before they spawn in game, or their pipes are well hidden. A direct example of this, is that wandering daddy longlegs spawn from pipes, and return to their pipes before the end of a cycle. This includes the daddies inside Five Pebbles, which makes the area significantly easier once the cycle timer has counted down entirely. It is important to understand various enemy interactions to help you build a cohesive and believable ecosystem for an area. Sandbox mode can help you learn which creature is where on the food chain. As well as looking at the interactions of creatures in other regions. Some creatures have very specific requirements for rooms they inhabit. A very game breaking example, is that big spiders and spitting spiders require the ability to reach every wall in a room in some fashion. By pole, or by invisible ceilings out of the camera. If they cannot, the game will lag very badly due to the spider’s failed pathfinding. Some creatures have a heavier performance impact on the game then others. <!--Sandbox mode can help you learn these, as it will show a notice that “too many of this creature will impact performance” when you begin to place too many.--> <!-- the arena threshold seems somewhat arbitrary in present day--> An example is that more then 4 daddy long legs on screen will often lead to lag. Unfortunate development gets around this problem by using the “stuckDaddy” object, as these daddies do not run wandering path finding checks. All creature types can be configured using the dev tool’s map editor to prefer, avoid, stay or be forbidden inside certain rooms while wandering, using Attraction tool. These spawn entries are simply where they will be created from when the player first enters a region. <span id="the-lineage-system"></span> === The Lineage System === Enemy nests may also be configured to use the lineage system. After being killed, this allows a creature to roll a dice at the end of a cycle, and in a certain percent, respawn as its next entry in the lineage. Due to the format however, you cannot decide how many enemies can spawn from the pipe. So a green lizard cannot turn into a hoard of 3 yellow lizards. Only a single yellow lizard. Enemy flags, and difficulty filters still work however. The format is as follows: <syntaxhighlight lang=""> LINEAGE : ROOM : PIPE : STARTENEMY-PERCENT, NEXTENEMY-PERCENT, FINALENEMY-0 </syntaxhighlight> PERCENT is a value between 0 and 1, and is the percent chance that the enemy will move onto its next form. You may have as many forms as you need. However, it is important to ALWAYS mark the last enemy in the lineage with a 0 percent chance to move on. Rain World will crash the moment it attempts to move to the next enemy in a lineage from the last. ==== Examples ==== A green lizard that spawns from pipe 2, that turns into a blue, and then into a red. With a 5% chance each time. <syntaxhighlight lang=""> LINEAGE : SU_B08 : 2 : Green-0.05, Blue-0.05, Red-0 </syntaxhighlight> A poleplant, with a specific height of 10 blocks, and spawning from pipe 3. That has a 10% chance to turn into a monster kelp <syntaxhighlight lang=""> LINEAGE : SU_A02 : 3 : Mimic-{10}-0.1, TentaclePlant-0 </syntaxhighlight> A empty pipe 3, that has a 1% chance to turn into a monster kelp. <syntaxhighlight lang=""> LINEAGE : SU_B02 : 3 : NONE-0.01, TentaclePlant-0 </syntaxhighlight> Lineage applies to offscreen creatures, as well as difficulties! This example from chimney canopy has a 20% chance to turn a vulture into a king vulture after being killed, but only on normal difficulty. <syntaxhighlight lang=""> (0)LINEAGE : OFFSCREEN : 0 : Vulture-0.2, KingVulture-0 </syntaxhighlight> == Bat Migration Blockages == Bat migration blockages section is bounded by <code>BAT MIGRATION BLOCKAGES</code> and <code>END BAT MIGRATION BLOCKAGES</code> tags. These are used specifically to prevent bat flies from entering a room, or pathing through the region to rooms on the other side of it. These are rarely used. However the room directly after the tutorial area in outskirts is set to be one. The format is simply to list each room line by line between the two tags. There are no unique flags. For the example in Outskirts, bat flies cannot enter room SU_A22 because it is between the tags: <syntaxhighlight lang="">BAT MIGRATION BLOCKAGES SU_A22 END BAT MIGRATION BLOCKAGES </syntaxhighlight> [[Category:Content Mods]] 711a48e59e09710998fa8fe820b5b6c1bfc52ded Custom Regions Support 0 101 236 166 2022-08-18T06:07:45Z Thalber 3 /* Runtime worldfile merging */ wikitext text/x-wiki {{Cleanup}} '''Custom Regions Support''' or '''CRS''' is a library/util mod that was created as an easier way to install [[Content Mods]], replacing file merging. It allows to install multiple region mods at once easily, quickly toggle them, and makes region development less messy. As of now, it is the primary way of installing any and all custom regions, and many of them are ''CRS-exclusive''. Full up-to-date README, source code and CRS-specific technical reference for modders can be found [[https://github.com/Garrakx/Custom-Regions on its GitHub]]. == Features == === Runtime worldfile merging === ''For basics of region architecture, see [[World File Format]]'' CRS attempts to smartly combine region world files and avoid room connectivity conflicts. It is the most effective if region mods don't distribute full modified copies of WORLD_XX.txt files for conflict-prone connection (such as vanilla region's WORLD_XX, when a modded region connects to it), and instead ''only include lines that need to be changed or added''. This is commonly referred to as "refining worldfiles". In addition to connection files, it can also merge region property files. === In-game downloader === CRS config menu allows the user to install most region packs from inside the game in one click, including their dependency DLLs, and also quickly toggle installed packs on and off. Downloader menu is reshuffled every day to give every CRS-published region a shot. === Region-conditional connections === Connections may be toggled depending on if a certain region is present: <syntaxhighlight lang=""> ROOMS (TM, !BL)roomA : roomB, roomD //only used if TM is installed and BL is not ENDROOMS </syntaxhighlight> This can be combined with unused vanilla behaviour of character-specific connections. === Connection fixer === Starting with v0.9.xx, CRS can attempt to fix some broken connections. This behaviour isn't a catchall but can make some conflicts less lethal. === Additional asset loading === CRS allows easily loading assets commonly bundled with most regions, such as music files, region splash art for passage/regions map screens, decals etc. === Misc === * Making previously hardcoded settings (electric gates, albino colouring on creatures, chance of salamander colouring etc) configurable with json files * Removing creature spawns * No-code addition of custom pearls * Adding unlockable arenas af81dc55f7998c98dc12e4b9bff7d297091c76c1 238 236 2022-08-18T06:09:31Z Thalber 3 /* Region-conditional connections */ wikitext text/x-wiki {{Cleanup}} '''Custom Regions Support''' or '''CRS''' is a library/util mod that was created as an easier way to install [[Content Mods]], replacing file merging. It allows to install multiple region mods at once easily, quickly toggle them, and makes region development less messy. As of now, it is the primary way of installing any and all custom regions, and many of them are ''CRS-exclusive''. Full up-to-date README, source code and CRS-specific technical reference for modders can be found [[https://github.com/Garrakx/Custom-Regions on its GitHub]]. == Features == === Runtime worldfile merging === ''For basics of region architecture, see [[World File Format]]'' CRS attempts to smartly combine region world files and avoid room connectivity conflicts. It is the most effective if region mods don't distribute full modified copies of WORLD_XX.txt files for conflict-prone connection (such as vanilla region's WORLD_XX, when a modded region connects to it), and instead ''only include lines that need to be changed or added''. This is commonly referred to as "refining worldfiles". In addition to connection files, it can also merge region property files. === In-game downloader === CRS config menu allows the user to install most region packs from inside the game in one click, including their dependency DLLs, and also quickly toggle installed packs on and off. Downloader menu is reshuffled every day to give every CRS-published region a shot. === Region-conditional connections === Connections may be toggled depending on if a certain region is present: <pre> ROOMS (TM, !BL)roomA : roomB, roomD //only used if TM is installed and BL is not ENDROOMS </pre> This can be combined with unused vanilla behaviour of character-specific connections. === Connection fixer === Starting with v0.9.xx, CRS can attempt to fix some broken connections. This behaviour isn't a catchall but can make some conflicts less lethal. === Additional asset loading === CRS allows easily loading assets commonly bundled with most regions, such as music files, region splash art for passage/regions map screens, decals etc. === Misc === * Making previously hardcoded settings (electric gates, albino colouring on creatures, chance of salamander colouring etc) configurable with json files * Removing creature spawns * No-code addition of custom pearls * Adding unlockable arenas 58fe72e6f06799329f4cd3532652a4e7fa6a10f0 Category:Content Mods 14 96 237 168 2022-08-18T06:08:12Z Thalber 3 wikitext text/x-wiki {{Cleanup}} Content mods are mods that consist primarily of asset files (e.g. sprite sheets, room files, audio etc). Content mods may contain new regions, sprite packs for player characters, arena level packs and so on. Content mods may depend on code mods in order to be loaded (such as [[CRS]]). They may be redistributed with supporting code libraries for additional features. For guidance on creating custom levels, see [[Level Editor]]. For region file structure, see [[World File Format]]. e619b04fe4c7552ec0a4e34f4851688beb530742 Region From The Ground Up 0 136 239 2022-08-18T06:21:29Z Thalber 3 Port RFG wikitext text/x-wiki {{Cleanup}} {{todo|target=page}} So you want to make a region, but you have no clue where to start! The idea of modding something so big is certainly daunting! However, looking at everything in small repeatable pieces will let you work step by step until one day you’ll suddenly have a finished region! However before that happens you need to learn some basics to get you started! Lets start with some terminology of the tools used! * [[Level Editor]] - This is the tool given to the modding community by the Rain World developers. These are the actual tools used to make Rain World. However much of its features and hotkeys are difficult and quirky to work with at first, but given enough time and use, the editor becomes an extremely powerful tool. * Unofficial level editor - This is a tool created by AndrewFM and Mikronaut to edit Rain World rooms before the official editor was released. While it lacks many features needed to make rooms. It does have the incredibly useful feature of being able to edit already exported rooms. As well as changing creature dens into doors, and vice versa. * [[Dev Tools]] - These are in game tools Rain World uses for editing room visual effects, sounds, and triggers. As well as the regions map, and the various other specific configurations of your room! * [[World File Format]] - This controls how your region (or any other region!) binds rooms together. As well as creature spawns! * Room settings text - These files are present for every room that you save a configuration for in the dev tools. It contains the placement of objects, sounds, room effects, and any other setting applied using the dev tools. I will not be giving a full control outline for every editor in this tutorial. If you need the editor’s controls, please see the full article on the specific tool you are using for their list of inputs and quirks. This article is an exercise in how to bring a level from an empty screen, to a fully fleshed out room. Largely following my own process. Don’t be afraid to branch out and try weirder things as you get comfortable with the editor! == Important terms and info == * A region is a large collection of connected rooms. Using a Worldfile to setup data inside them. * A room is stored as several files that contain: ** Geometry and pathfinding data ** Room graphics, one .PNG file per camera ** Settings file containing additional data such as room effects, sound triggers and placed objects (defined in [[Dev Tools]]) * The editor can only export the collision and graphics for rooms, Dev Tools are used to set the colors and effects. * Every room needs at least one valid door in order to be connected * By default, the editor will create a room the correct size for a single screen, with a single camera already set up. <!--This is why the guide assumes only a single screen to help you learn to use the editor.--> By default, a single room is 72 x 43. '''Changing room size after some tiles have been added breaks the tiles, and has a chance of corrupting the level project with uneraseable invisible tiles!''' == Setting Up == [[File:rfg-1.png|thumb|none|alt=1|1]] Once you open the official editor for the first time. you will be greeted with a file select. It is advised to make a folder for your rooms to keep them organized before you open the editor. Use the arrow keys to navigate into that folder, and press N to make a new room. You will then be greeted with the editor’s main menu. === Saving, and name quirks: === Before we do anything, lets save our room. It is REQUIRED that you start all of your rooms names with a region prefix. You can check the Rain World, World folder for the regions in game. We will be using SU_ the prefix for outskirts, at least until we have several rooms for our region later, or you are confident enough to begin making rooms for your own region. Secondly, NEVER use spaces. Always use an underscore _ to separate your name’s sections. Examples of correct room names: * SU_test01 * SU_myroom * SU_my_room * SU_another_room * SU_lotsandlotsofroom15 * SU_A04 The developers often used the letter (A, B, C…, J…) after the underscore _ to track the number of cameras in the room (for non-shelter (S) rooms), but this is not required. Examples of actual rooms in the game: * SU_A05 - small Outskirts room with 1 camera (A) * SU_B08 - larger Outskirts room with 2 cameras (B) * HI_C14 - wide Industrial Complex room with 3 cameras (C) * CC_D01 - tall Chimney Canopy room with 4 cameras (D) * SL_F01 - Shoreline room with 6 cameras (F) * UW_J01 - huge room in The Wall with 10 cameras (J) So now. You are ready to begin painting! == A Blank Canvas == [[File:rfg-2.png|thumb|none|alt=2|2]] Click the geometry editor button to begin painting your level’s basic geometry. However, before we do anything. We will first clear all the layer using the “clear all” tool. Use the arrow keys while the mouse is over the tile grid to change tools. Once the red box is over the X shaped tool. Used the numpad to navigate to the top left corner, click once to start drawing the rectangle of the clear tool, and navigate to the bottom right to place the other corner. When you are finished all the solid walls in the room will be removed. Leaving you with a completely blank canvas to work from. A “fuzzy” grey border marks the very edge of a room. Where tiles no longer exist to the game. The white rectangle is the game play border Anything outside of this will repeat off into the distance, this ONLY applies to the room’s collision. Visually they will be fine. All room in Rain World use these borders. For a more simple explanation. Keep everything related to gameplay inside the white rectangle! Anything outside will only show up visually, but will not act the same as they would inside the rectangle! == Blocking It Out == [[File:rfg-3.png|thumb|none|alt=3|3]] Lets start painting out the shapes we want for our basic level! This seems like a bit sudden of a jump, but only a few moments of messing around in the editor will let you achieve what you see in the screenshot! Short cuts to doors and dens require walls to be placed in specific ways around them. The [[level-editor/Geometry-Editor.html|Geometry Editor]] article goes into more depth about properly connecting short cuts, doors, and dens. For now, we will simply place walls, some poles, and at least one “Entrance” to the room. The Dens seen in the screenshot are optional. Only one door is required for this tutorial. == A Test Render == [[File:rfg-4.png|thumb|none|alt=4|4]] Before we move on; Lets do another save. So if anything goes wrong we won’t lose the level geometry we now have. Press 1 on the number row to return to the main menu, and press the save button! Press enter in the name field to save the room without changing the name of it. It is now time to do a test render of our room so we can see if it plays correctly in game! First, we need to click “Text Output” to save the levels collision data, and then press “Render Level.” The editor will appear to freeze for a few moments. This is normal! Do not be worried, or attempt to close the editor! Eventually the editor will begin processing each layer of the room. Before it will render the rooms data into a red and black image. The files will be output into the “Levels” folder by the editor’s executable. The files ROOMNAME.txt and ROOMNAME_1.png are the exported version of your room, for use by Rain Worlds engine. Lets get to seeing our room in game! == Our First Link == For now. We will be using outskirts as a quick way to test our room. We don’t have our own region yet after all! There is already an easy to use DISCONNECTED door in outskirts, close to the start of the game. Lets move our room files to where they are needed! First. Copy the ROOMNAME.txt and ROOMNAME_1.png files from the editor’s level export folder. Then navigate to “Rain World”. Inside you will see various other room files, and their settings file. For now, we will simply paste our room files into this folder. Second. We will go one folder up. So we are inside the “SU” region folder. In here you will see Outskirt’s World.txt file. The detail of this file are in this article: [[World-File-Format.html|World File Format]]. However, for the purpose of this tutorial, we will be following the next steps to install our room to Outskirts! Third. Open World_SU.txt. Inside we will see several door connections, creature spawns, and other region related data. Look for the line: * SU_A63 : SU_B12, SU_A37, DISCONNECTED This room has a disconnected door we can use to hook our room into easily! Lets add our room into the file! At the end of the end of the ROOMS section, but before the END ROOMS tag, add in our room’s name. Followed by a : Then add SU_A63. This will link our door to SU_A63. My room’s entry looks like this: * SU_myroom : SU_A63 We now need to make sure SU_A63 connects to our room as well! We simply need to change DISCONNECTED into our rooms name. Mine looks like: * SU_A63 : SU_B12, SU_A37, SU_myroom We can now start Rain World! If this has all been done correctly. Then you will be able to load your file without it crashing to a grey screen. Simply navigate to SU_A63 to see the freshly added connection! You can peak into SU’s “Rooms” folder, and find SU_A63_1.png to see what the room looks like to know where it is in game! == Making Mistakes == [[File:rfg-5.png|thumb|none|alt=5|5]] Our first room is pretty rough! Not everything will be perfect of course! This is a time to see if everything in our geometry works right! If pits are impossible to jump across, or if a jump is just a little our of reach. This is the time to tweak our level till we are happy with the layout. Render times are very fast with just a single layer and some walls after all! Don’t be afraid of mistakes at this point. Just fix them and tweak until your room feels like it is playable, and there are no locations that you can become stuck in. Repeat the steps above to edit, re-render, and re-install the room. You will no longer need to link the level to the world again! You only need to update the room files and image. You do not even need to close Rain World to test these changes. Simply dying, and returning to the room is enough to cause the room to reload for you to test the new collisions! == A Start To Detailing == [[File:rfg-6.png|thumb|none|alt=6|6]] This looks like another crazy jump! But once you get used to the materials the editor gives you, the tile editor will become a playground, and you may even start designing your levels with it, and instead use the geometry editor just to compliment your tiles! It will all come to you as your understanding and comfort of the editor increases. The details I’ve applied myself, have been to paint various materials in the same style Outskirts uses. Large metal plates surrounding dense pipes on corners. Concrete as the base material. The rare inclusion of pipes and machines. Along with a few things I enjoy using in my own levels. Such as large signs from the Misc category, and the insides of large pipes! The tile menu can be navigated using WASD keys. Many large tiles have a collision requirement. Holding G while clicking will automatically place the required geometry for you. This allows you to build things like pipes or complex machines without revisiting the geometry editor, or to construct rooms almost entirely out of tiles. However, you will still need to visit the geometry editor at some point for the bulk of your room’s padding. Where you will paint the traditional tile “materials” over solid walls. The colored dots in the picture are walls painted with a specific material. These are applied as the level is rendered! For now we are still just focusing on layer 1! == A Second Render == [[File:rfg-7.png|thumb|none|alt=7|7]] Things are starting to come together now! We can do a second little peak at how the room plays. After all, we’ve likely done some tweaks with our detailing. Something is still missing however. Using only the first layer of Rain World’s rooms can only give us so much detail! This level needs some DEPTH! == Depth, and the Art of Backgrounds == [[File:rfg-8.png|thumb|none|alt=8|8]] Lets head back into the editor! In the geometry editor, use the layer tool in the bottom left to change to layer 2, and paint over the places we want to place a “back wall” to our room! This layer is also one that creatures can climb on. Blue lizards often do this! Some details on the first layer will also “bleed” into layers behind them. This happens most with the insides of pipes and large chimneys! You can see in the screenshot that I have not placed any layer 2 walls behind the pipe segments at the bottom of the room’s vat area. I’ve done this so that the back wall will not cover over the inside of the pipes during the render! Once you are done painting, save, export text, and do a render! Lets do another test of how our level looks! == A Third Render == [[File:rfg-9.png|thumb|none|alt=9|9]] Yet another render, and more to see and tweak! We can fix any mistakes easily as we go. You can also skip each rendering step, and do all the layers at once if you are confident with the editor! I’ll be doing a third layer, and correcting all the issues on layer 2 by the next section. All the info you need is in the official editor’s article here: [[level-editor/Official-Level-Editor.html|Official Level Editor]]. There is also a large guide of all tiles and materials, and how they look once rendered here: https://imgur.com/a/Vz3Kk The next steps involve tweaking, rendering, retweaking, and rerendering until you are happy with the base design of your level! Remember, that some creatures use layer 2 to climb on walls, but layer 3 is far enough in the background for nothing to interact with it! Layer 1 is solid to all creatures with few if at all exceptions. Make sure you cannot get trapped in your level! == Effects and You == [[File:rfg-10.png|thumb|none|alt=10|10]] It’s time to start painting! Now that you’ve solved any issues on your tile layers, and painted yourself a background layer. You are now ready to start painting effects! Remember though. Each effect slows down the render of the level quite a bit. From now on it will begin to get more time consuming to fix mistakes in the level! Especially once you start making larger rooms! Effects are what make Rain World rooms look special. They alter, distort, and deform your tiles. Grow plants, and even alter tiles entirely! The effects editor has an example image of every effect, and its basic usage outline in this article: [[level-editor/Effect-Editor|Effects Editor]]. For the basics though! BlackGoo and Slime; These two effects are used in nearly every screen in Rain World to some degree! Slime makes every tile look slightly drippy and goopy. Like a mess has been rubbed onto them. BlackGoo forms the outer “shadow” of rooms. Both of these work together to make your room look less repetitive and clean! == Yet another rendering == [[File:rfg-11.png|thumb|none|alt=11|11]] Look how far we’ve come! From an empty screen with nothing. To a room that feels like it is simply missing “something” before it is finished! Things like the brickwork along the sides passing over the BlackGoo( It only applies itself over certain materials!) can be corrected using large junk or dirt where you would want the BlackGoo down there. You can also apply other effects till you are happy with the room. This includes everything from rubble, distortions, plants, and even daddy long leg corrupted walls! The only limits is your imagination to making effects work together, and the tiles you have to use! Once you’ve applied the effects you want, and have re-rendered till the level looks right. Next up is to add some props to our room! == Fancy Props and Design == [[File:rfg-12.png|thumb|none|alt=12|12]] Remember to always save and keep backups! Some editor tabs can be more fussy then others! Props are used to detail your room even further. Allowing you to place details without the grid, and at any angle and distorted shape you want! The control are outlined in the article here: [[level-editor/Prop-Editor.html|Prop Editor]]. While this is not too complex of a section. Adding a few proper can help break the rather straight geometry normally present in Rain World’s levels by giving them some more curved shapes to look at. Such as tubes and valves between containers or machines! Once you are all setup, we can render and move onto using the dev tools to configure the rooms more fine details! Remember. You can always re-render and re-export a level as many times as you need. At no point does a level become impossible to edit. With the one exception of losing its project save file! == Dev tool configurations == [[File:rfg-13.png|thumb|none|alt=13|13]] We can now move onto using the [[dev-tools/Dev-Tools.html|Dev Tools]] to configure the level’s more detailed settings! Everything from the room’s colors, effects, and even how the rain timer affects this room! Want a section of outskirts with some kind of lightning machine? Go ahead! Want to make a flooding cave system? It’s all in here! The room’s palette is not tied to the region. However most regions have “templates” that you can use to automatically set room settings to. Instead of needing to do each room one by one the same way. You can change anything you need to away from the template default, or click “NONE” beneath in the template section to use purely your own settings. The rooms palette can also be configured to fade between it, and another palette. Allowing you to configure the exact colors you would need. The various effects can also be configured to use Color1 or Color2 of the effect palettes. These are used to set the colors of plants. Giant signs, and even daddy long leg corruption! Exploring the dev tools documentation will give you far more info and ideas then me directly telling you every possible situation. Remember that some objects and room settings require a reload of the room to appear! Don’t forget to add sounds and some environmental ambience to flesh out your room, to make it feel like a unique location in this world! ''A very IMPORTANT notice! Be sure to click the save button before you reload the room'' somehow! Or your changes will be lost! All of these configurations are save to ROOMNAME_settings.txt. == Over and Over Again == [[File:rfg-14.png|thumb|none|alt=14|14]] The process of making a full region is filled with this! Making rooms from the ground up, detailing and configuring them, before linking another room onto the chain. The only real difference is that you are doing so from the gates of your own region, instead of a small room connected to the side of outskirts! There are already a few pages of documentation related to connecting in a new region yourself! The main one can be found here: [[Adding-A-New-Region.html|Adding new Regions]]. The details of how to setup creatures and connections for the region are here: [[World-File-Format.html|World File Format]]. Finally, the dev tool’s map editor for making your region properly show as a map in game is here: [[dev-tools/Map.html|Map Tab]]. I’ll likely be expanding this guide at some point in the future, but for now this is the basics of how to create a room from scratch! Look through the other articles for things like: Raising the water level, setting up creature spawns, understanding doors, adding food, placing objects and plants, adding sounds and effects, specific room triggers, and the various special room settings! And remember! Have fun! == Why Do My Rooms Crash? == There are multiple reasons Rain World will dislike your rooms or connections. These are a few common, and more niche reasons why the game may be crashing. === Doors outside of room bounds: === ALWAYS place every part of a short cut’s path inside the room’s boundary. Any short cut paths outside of it are ignored and will break the game when loaded. Crashing to a grey screen on file load. === Accidental Doors and Dens: === The editor is a strange tool. It also has a second cursor in geometry mode… for some reason. An accidental key press may have placed a den, short cut entrance, or other kind of door in the room without proper connections. Take a peak over your room for any issues. === Incorrect Region Prefix: === the prefix at the start of a room file should match the region you are placing it inside. For this guide we focus on tests rooms inside of outskirts ( SU_ ). If you are bringing these rooms to a custom region by renaming them, be sure to open the room’s data file, and edit the first line to match the renamed version of the file. 3dcf34a64626819507d91e03f1e7881681ef3c4e 240 239 2022-08-18T06:21:58Z Thalber 3 wikitext text/x-wiki {{Cleanup}} {{todo|target=page}} So you want to make a region, but you have no clue where to start! The idea of modding something so big is certainly daunting! However, looking at everything in small repeatable pieces will let you work step by step until one day you’ll suddenly have a finished region! However before that happens you need to learn some basics to get you started! Lets start with some terminology of the tools used! * [[Level Editor]] - This is the tool given to the modding community by the Rain World developers. These are the actual tools used to make Rain World. However much of its features and hotkeys are difficult and quirky to work with at first, but given enough time and use, the editor becomes an extremely powerful tool. * Unofficial level editor - This is a tool created by AndrewFM and Mikronaut to edit Rain World rooms before the official editor was released. While it lacks many features needed to make rooms. It does have the incredibly useful feature of being able to edit already exported rooms. As well as changing creature dens into doors, and vice versa. * [[Dev Tools]] - These are in game tools Rain World uses for editing room visual effects, sounds, and triggers. As well as the regions map, and the various other specific configurations of your room! * [[World File Format]] - This controls how your region (or any other region!) binds rooms together. As well as creature spawns! * Room settings text - These files are present for every room that you save a configuration for in the dev tools. It contains the placement of objects, sounds, room effects, and any other setting applied using the dev tools. I will not be giving a full control outline for every editor in this tutorial. If you need the editor’s controls, please see the full article on the specific tool you are using for their list of inputs and quirks. This article is an exercise in how to bring a level from an empty screen, to a fully fleshed out room. Largely following my own process. Don’t be afraid to branch out and try weirder things as you get comfortable with the editor! == Important terms and info == * A region is a large collection of connected rooms. Using a Worldfile to setup data inside them. * A room is stored as several files that contain: ** Geometry and pathfinding data ** Room graphics, one .PNG file per camera ** Settings file containing additional data such as room effects, sound triggers and placed objects (defined in [[Dev Tools]]) * The editor can only export the collision and graphics for rooms, Dev Tools are used to set the colors and effects. * Every room needs at least one valid door in order to be connected * By default, the editor will create a room the correct size for a single screen, with a single camera already set up. <!--This is why the guide assumes only a single screen to help you learn to use the editor.--> By default, a single room is 72 x 43. '''Changing room size after some tiles have been added breaks the tiles, and has a chance of corrupting the level project with uneraseable invisible tiles!''' == Setting Up == [[File:rfg-1.png|thumb|none|alt=1|1]] Once you open the official editor for the first time. you will be greeted with a file select. It is advised to make a folder for your rooms to keep them organized before you open the editor. Use the arrow keys to navigate into that folder, and press N to make a new room. You will then be greeted with the editor’s main menu. === Saving, and name quirks: === Before we do anything, lets save our room. It is REQUIRED that you start all of your rooms names with a region prefix. You can check the Rain World, World folder for the regions in game. We will be using SU_ the prefix for outskirts, at least until we have several rooms for our region later, or you are confident enough to begin making rooms for your own region. Secondly, NEVER use spaces. Always use an underscore _ to separate your name’s sections. Examples of correct room names: * SU_test01 * SU_myroom * SU_my_room * SU_another_room * SU_lotsandlotsofroom15 * SU_A04 The developers often used the letter (A, B, C…, J…) after the underscore _ to track the number of cameras in the room (for non-shelter (S) rooms), but this is not required. Examples of actual rooms in the game: * SU_A05 - small Outskirts room with 1 camera (A) * SU_B08 - larger Outskirts room with 2 cameras (B) * HI_C14 - wide Industrial Complex room with 3 cameras (C) * CC_D01 - tall Chimney Canopy room with 4 cameras (D) * SL_F01 - Shoreline room with 6 cameras (F) * UW_J01 - huge room in The Wall with 10 cameras (J) So now. You are ready to begin painting! == A Blank Canvas == [[File:rfg-2.png|thumb|none|alt=2|2]] Click the geometry editor button to begin painting your level’s basic geometry. However, before we do anything. We will first clear all the layer using the “clear all” tool. Use the arrow keys while the mouse is over the tile grid to change tools. Once the red box is over the X shaped tool. Used the numpad to navigate to the top left corner, click once to start drawing the rectangle of the clear tool, and navigate to the bottom right to place the other corner. When you are finished all the solid walls in the room will be removed. Leaving you with a completely blank canvas to work from. A “fuzzy” grey border marks the very edge of a room. Where tiles no longer exist to the game. The white rectangle is the game play border Anything outside of this will repeat off into the distance, this ONLY applies to the room’s collision. Visually they will be fine. All room in Rain World use these borders. For a more simple explanation. Keep everything related to gameplay inside the white rectangle! Anything outside will only show up visually, but will not act the same as they would inside the rectangle! == Blocking It Out == [[File:rfg-3.png|thumb|none|alt=3|3]] Lets start painting out the shapes we want for our basic level! This seems like a bit sudden of a jump, but only a few moments of messing around in the editor will let you achieve what you see in the screenshot! Short cuts to doors and dens require walls to be placed in specific ways around them. The [[level-editor/Geometry-Editor.html|Geometry Editor]] article goes into more depth about properly connecting short cuts, doors, and dens. For now, we will simply place walls, some poles, and at least one “Entrance” to the room. The Dens seen in the screenshot are optional. Only one door is required for this tutorial. == A Test Render == [[File:rfg-4.png|thumb|none|alt=4|4]] Before we move on; Lets do another save. So if anything goes wrong we won’t lose the level geometry we now have. Press 1 on the number row to return to the main menu, and press the save button! Press enter in the name field to save the room without changing the name of it. It is now time to do a test render of our room so we can see if it plays correctly in game! First, we need to click “Text Output” to save the levels collision data, and then press “Render Level.” The editor will appear to freeze for a few moments. This is normal! Do not be worried, or attempt to close the editor! Eventually the editor will begin processing each layer of the room. Before it will render the rooms data into a red and black image. The files will be output into the “Levels” folder by the editor’s executable. The files ROOMNAME.txt and ROOMNAME_1.png are the exported version of your room, for use by Rain Worlds engine. Lets get to seeing our room in game! == Our First Link == For now. We will be using outskirts as a quick way to test our room. We don’t have our own region yet after all! There is already an easy to use DISCONNECTED door in outskirts, close to the start of the game. Lets move our room files to where they are needed! First. Copy the ROOMNAME.txt and ROOMNAME_1.png files from the editor’s level export folder. Then navigate to “Rain World”. Inside you will see various other room files, and their settings file. For now, we will simply paste our room files into this folder. Second. We will go one folder up. So we are inside the “SU” region folder. In here you will see Outskirt’s World.txt file. The detail of this file are in this article: [[World-File-Format.html|World File Format]]. However, for the purpose of this tutorial, we will be following the next steps to install our room to Outskirts! Third. Open World_SU.txt. Inside we will see several door connections, creature spawns, and other region related data. Look for the line: * SU_A63 : SU_B12, SU_A37, DISCONNECTED This room has a disconnected door we can use to hook our room into easily! Lets add our room into the file! At the end of the end of the ROOMS section, but before the END ROOMS tag, add in our room’s name. Followed by a : Then add SU_A63. This will link our door to SU_A63. My room’s entry looks like this: * SU_myroom : SU_A63 We now need to make sure SU_A63 connects to our room as well! We simply need to change DISCONNECTED into our rooms name. Mine looks like: * SU_A63 : SU_B12, SU_A37, SU_myroom We can now start Rain World! If this has all been done correctly. Then you will be able to load your file without it crashing to a grey screen. Simply navigate to SU_A63 to see the freshly added connection! You can peak into SU’s “Rooms” folder, and find SU_A63_1.png to see what the room looks like to know where it is in game! == Making Mistakes == [[File:rfg-5.png|thumb|none|alt=5|5]] Our first room is pretty rough! Not everything will be perfect of course! This is a time to see if everything in our geometry works right! If pits are impossible to jump across, or if a jump is just a little our of reach. This is the time to tweak our level till we are happy with the layout. Render times are very fast with just a single layer and some walls after all! Don’t be afraid of mistakes at this point. Just fix them and tweak until your room feels like it is playable, and there are no locations that you can become stuck in. Repeat the steps above to edit, re-render, and re-install the room. You will no longer need to link the level to the world again! You only need to update the room files and image. You do not even need to close Rain World to test these changes. Simply dying, and returning to the room is enough to cause the room to reload for you to test the new collisions! == A Start To Detailing == [[File:rfg-6.png|thumb|none|alt=6|6]] This looks like another crazy jump! But once you get used to the materials the editor gives you, the tile editor will become a playground, and you may even start designing your levels with it, and instead use the geometry editor just to compliment your tiles! It will all come to you as your understanding and comfort of the editor increases. The details I’ve applied myself, have been to paint various materials in the same style Outskirts uses. Large metal plates surrounding dense pipes on corners. Concrete as the base material. The rare inclusion of pipes and machines. Along with a few things I enjoy using in my own levels. Such as large signs from the Misc category, and the insides of large pipes! The tile menu can be navigated using WASD keys. Many large tiles have a collision requirement. Holding G while clicking will automatically place the required geometry for you. This allows you to build things like pipes or complex machines without revisiting the geometry editor, or to construct rooms almost entirely out of tiles. However, you will still need to visit the geometry editor at some point for the bulk of your room’s padding. Where you will paint the traditional tile “materials” over solid walls. The colored dots in the picture are walls painted with a specific material. These are applied as the level is rendered! For now we are still just focusing on layer 1! == A Second Render == [[File:rfg-7.png|thumb|none|alt=7|7]] Things are starting to come together now! We can do a second little peak at how the room plays. After all, we’ve likely done some tweaks with our detailing. Something is still missing however. Using only the first layer of Rain World’s rooms can only give us so much detail! This level needs some DEPTH! == Depth, and the Art of Backgrounds == [[File:rfg-8.png|thumb|none|alt=8|8]] Lets head back into the editor! In the geometry editor, use the layer tool in the bottom left to change to layer 2, and paint over the places we want to place a “back wall” to our room! This layer is also one that creatures can climb on. Blue lizards often do this! Some details on the first layer will also “bleed” into layers behind them. This happens most with the insides of pipes and large chimneys! You can see in the screenshot that I have not placed any layer 2 walls behind the pipe segments at the bottom of the room’s vat area. I’ve done this so that the back wall will not cover over the inside of the pipes during the render! Once you are done painting, save, export text, and do a render! Lets do another test of how our level looks! == A Third Render == [[File:rfg-9.png|thumb|none|alt=9|9]] Yet another render, and more to see and tweak! We can fix any mistakes easily as we go. You can also skip each rendering step, and do all the layers at once if you are confident with the editor! I’ll be doing a third layer, and correcting all the issues on layer 2 by the next section. All the info you need is in the official editor’s article here: [[level-editor/Official-Level-Editor.html|Official Level Editor]]. There is also a large guide of all tiles and materials, and how they look once rendered here: https://imgur.com/a/Vz3Kk The next steps involve tweaking, rendering, retweaking, and rerendering until you are happy with the base design of your level! Remember, that some creatures use layer 2 to climb on walls, but layer 3 is far enough in the background for nothing to interact with it! Layer 1 is solid to all creatures with few if at all exceptions. Make sure you cannot get trapped in your level! == Effects and You == [[File:rfg-10.png|thumb|none|alt=10|10]] It’s time to start painting! Now that you’ve solved any issues on your tile layers, and painted yourself a background layer. You are now ready to start painting effects! Remember though. Each effect slows down the render of the level quite a bit. From now on it will begin to get more time consuming to fix mistakes in the level! Especially once you start making larger rooms! Effects are what make Rain World rooms look special. They alter, distort, and deform your tiles. Grow plants, and even alter tiles entirely! The effects editor has an example image of every effect, and its basic usage outline in this article: [[level-editor/Effect-Editor|Effects Editor]]. For the basics though! BlackGoo and Slime; These two effects are used in nearly every screen in Rain World to some degree! Slime makes every tile look slightly drippy and goopy. Like a mess has been rubbed onto them. BlackGoo forms the outer “shadow” of rooms. Both of these work together to make your room look less repetitive and clean! == Yet another rendering == [[File:rfg-11.png|thumb|none|alt=11|11]] Look how far we’ve come! From an empty screen with nothing. To a room that feels like it is simply missing “something” before it is finished! Things like the brickwork along the sides passing over the BlackGoo( It only applies itself over certain materials!) can be corrected using large junk or dirt where you would want the BlackGoo down there. You can also apply other effects till you are happy with the room. This includes everything from rubble, distortions, plants, and even daddy long leg corrupted walls! The only limits is your imagination to making effects work together, and the tiles you have to use! Once you’ve applied the effects you want, and have re-rendered till the level looks right. Next up is to add some props to our room! == Fancy Props and Design == [[File:rfg-12.png|thumb|none|alt=12|12]] Remember to always save and keep backups! Some editor tabs can be more fussy then others! Props are used to detail your room even further. Allowing you to place details without the grid, and at any angle and distorted shape you want! The control are outlined in the article here: [[level-editor/Prop-Editor.html|Prop Editor]]. While this is not too complex of a section. Adding a few proper can help break the rather straight geometry normally present in Rain World’s levels by giving them some more curved shapes to look at. Such as tubes and valves between containers or machines! Once you are all setup, we can render and move onto using the dev tools to configure the rooms more fine details! Remember. You can always re-render and re-export a level as many times as you need. At no point does a level become impossible to edit. With the one exception of losing its project save file! == Dev tool configurations == [[File:rfg-13.png|thumb|none|alt=13|13]] We can now move onto using the [[dev-tools/Dev-Tools.html|Dev Tools]] to configure the level’s more detailed settings! Everything from the room’s colors, effects, and even how the rain timer affects this room! Want a section of outskirts with some kind of lightning machine? Go ahead! Want to make a flooding cave system? It’s all in here! The room’s palette is not tied to the region. However most regions have “templates” that you can use to automatically set room settings to. Instead of needing to do each room one by one the same way. You can change anything you need to away from the template default, or click “NONE” beneath in the template section to use purely your own settings. The rooms palette can also be configured to fade between it, and another palette. Allowing you to configure the exact colors you would need. The various effects can also be configured to use Color1 or Color2 of the effect palettes. These are used to set the colors of plants. Giant signs, and even daddy long leg corruption! Exploring the dev tools documentation will give you far more info and ideas then me directly telling you every possible situation. Remember that some objects and room settings require a reload of the room to appear! Don’t forget to add sounds and some environmental ambience to flesh out your room, to make it feel like a unique location in this world! ''A very IMPORTANT notice! Be sure to click the save button before you reload the room'' somehow! Or your changes will be lost! All of these configurations are save to ROOMNAME_settings.txt. == Over and Over Again == [[File:rfg-14.png|thumb|none|alt=14|14]] The process of making a full region is filled with this! Making rooms from the ground up, detailing and configuring them, before linking another room onto the chain. The only real difference is that you are doing so from the gates of your own region, instead of a small room connected to the side of outskirts! There are already a few pages of documentation related to connecting in a new region yourself! The main one can be found here: [[Adding-A-New-Region.html|Adding new Regions]]. The details of how to setup creatures and connections for the region are here: [[World-File-Format.html|World File Format]]. Finally, the dev tool’s map editor for making your region properly show as a map in game is here: [[dev-tools/Map.html|Map Tab]]. I’ll likely be expanding this guide at some point in the future, but for now this is the basics of how to create a room from scratch! Look through the other articles for things like: Raising the water level, setting up creature spawns, understanding doors, adding food, placing objects and plants, adding sounds and effects, specific room triggers, and the various special room settings! And remember! Have fun! == Why Do My Rooms Crash? == There are multiple reasons Rain World will dislike your rooms or connections. These are a few common, and more niche reasons why the game may be crashing. === Doors outside of room bounds: === ALWAYS place every part of a short cut’s path inside the room’s boundary. Any short cut paths outside of it are ignored and will break the game when loaded. Crashing to a grey screen on file load. === Accidental Doors and Dens: === The editor is a strange tool. It also has a second cursor in geometry mode… for some reason. An accidental key press may have placed a den, short cut entrance, or other kind of door in the room without proper connections. Take a peak over your room for any issues. === Incorrect Region Prefix: === the prefix at the start of a room file should match the region you are placing it inside. For this guide we focus on tests rooms inside of outskirts ( SU_ ). If you are bringing these rooms to a custom region by renaming them, be sure to open the room’s data file, and edit the first line to match the renamed version of the file. [[Category:Content Mods]] c5b7368f9a8448e0ee9f1a4b2f507bfe1731b89e File:hunterAngy.png 6 137 241 2022-08-18T06:24:55Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 Template:Cleanup 10 88 242 180 2022-08-18T06:27:13Z Thalber 3 wikitext text/x-wiki <includeonly><div class="nomobile">{{Ambox | image = <p><span style="margin-right:15px>[[File:Hardhatcat.png|middle|47px]]</span> | type = '''This article needs clean-up to meet quality standards.''' | info = Our community is working hard to rehaul this page. In the meantime, feel free to help {{fullurl|{{FULLPAGENAME}}|action=edit{{#if: {{{1|}}} | &section={{{1}}} }}|text=improve}} what's currently written.</p> | border = gray }}</div> [[Category:Cleanup needed]] </includeonly> <noinclude> Usage: <nowiki>{{Cleanup}}</nowiki> {{Cleanup}} </noinclude> 08e7f71fce655d48c02eb553167f15c4763285c4 245 242 2022-08-18T06:36:24Z Thalber 3 wikitext text/x-wiki <includeonly><div class="nomobile">{{Ambox | image = <p><span style="margin-right:15px>[[File:Hardhatcat.png|middle|47px]]</span> | type = '''This article needs clean-up to meet quality standards.''' | info = This page does not meet quality standards and needs structural and/or tonal cleanup. Feel free to help {{fullurl|{{FULLPAGENAME}}|action=edit{{#if: {{{1|}}} | &section={{{1}}} }}|text=improve}} it.</p> | border = gray }}</div> [[Category:Cleanup needed]] </includeonly> <noinclude> Usage: <nowiki>{{Cleanup}}</nowiki> {{Cleanup}} </noinclude> 99a4e5468264cde163eadeef88ea0c07473c713f 246 245 2022-08-18T06:38:15Z Thalber 3 wikitext text/x-wiki <includeonly><div class="nomobile">{{Ambox | image = <p><span style="margin-right:15px>[[File:Hardhatcat.png|middle|47px]]</span> | type = '''Cleanup needed''' | info = This article needs structural or tonal clean-up to meet quality standards. Feel free to help {{fullurl|{{FULLPAGENAME}}|action=edit{{#if: {{{1|}}} | &section={{{1}}} }}|text=improve}} it.</p> | border = gray }}</div> [[Category:Cleanup needed]] </includeonly> <noinclude> Usage: <nowiki>{{Cleanup}}</nowiki> {{Cleanup}} </noinclude> 5d566fe91cacbc6278d97c715e7de0f5cec8ef35 File:monkPower.png 6 138 243 2022-08-18T06:30:58Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 Template:todo 10 120 244 189 2022-08-18T06:33:55Z Thalber 3 monkpower wikitext text/x-wiki <includeonly><div class="nomobile">{{Ambox | image = <p><span style="margin-right:15px>[[File:monkPower.png|47px|middle]]</span> | type = '''This {{{target|section}}} is unfinished''' | info = This {{{target|section}}} is lacking some / all of critical information.</p> | border = gray }}</div> [[Category:Unfinished]] </includeonly> <noinclude> Usage: <nowiki> {{todo}} {{todo|target=table}} (target defaults to "section") </nowiki> {{todo}} {{todo|target=table}} </noinclude> 8017b3874faf6faa7d5eef3d92c45ce227b5fc25 BOI 0 110 247 163 2022-08-18T08:38:53Z Thalber 3 wikitext text/x-wiki '''BOI''' ''(an abbreviation of a horrendous pun)'' is an external mod manager for [[BepInEx]] initially created with the intent of making migration from [[Partiality]] easier. Glued together in Windows Forms and erratically maintained by a terminally clueless specimen since late 2020, it is a tall tower of bodges that somehow still stands. A hatchling-friendly tutorial to using it can be found [https://youtu.be/brDN_8uN6-U on YouTube]. Source code and releases can be found [https://github.com/Rain-World-Modding/BOI on GitHub]. == Features == === GUI wrapper === BOI has a somewhat straightforward UI for loading/enabling/disabling mods of most common kinds. It imitates the folder behaviour of [[Partiality]] (everything is stored in <code>Rain World/Mods/</code> before being moved to BepInEx active dirs) and attempts to automate some actions counterintuitive to the end user (like renaming assembly files for [[MonoModPatches]]). === Auto-installer === BOI can quickly install a latest valid [[BepInEx]] package and some of the more commonly used mods from [[AUDB]]. === Misc === * Detecting potentially faulty mods * Save state backups * Mod tags and bulk toggling * Post-PL folder cleanup * GUI wrappers for some mod configs == Installation == # Download latest release and unpack the archive. #* It is recommended to keep BOI in a separate folder. #* Make sure that all of archive contents are next to BOI.exe # Run BOI.exe. Press <code>Select path to game</code> ## Navigate to the game's .exe file ## Open it ## Press the same button again [[Category:RW-Specific Tools]] 3070da162b9a3f0923470685fcb24527ebd72d11 Contribution Guidelines 0 139 250 2022-08-18T09:16:21Z Thalber 3 Create guidelines wikitext text/x-wiki This page contains editing, styling, and page structure guidelines to be used {{SITENAME}}. It is recommended all editors follow them to whatever extent is reasonable in given context. The guidelines are subject to change. == Template use == Mark pages requiring visual / stylistic / tonal cleanup with [[Template:Cleanup]]. Mark pages / sections / other items missing crucial information with [[Template:todo]]. == Page structure == === Tool pages === Put installation remarks and instructions under a <code>== Installation ==</code> section. Put usage remarks and instructions under a <code>== Usage ==</code> section. == Misc == Put text that must be read exactly by the user (file paths, class/method names, string literals etc) in <code><nowiki><code> </code></nowiki></code> tags if it is inline, <code><nowiki><pre> </pre></nowiki></code> if it is multiline (unless it is otherwise clearly separated, i.e. being the sole thing occupying a table cell). 1234b807d8a47879eef54a77897f75ddb77881d3 Contribution Guidelines 0 139 251 250 2022-08-18T09:16:38Z Thalber 3 Protected "[[Contribution Guidelines]]" ([Edit=Allow only administrators] (indefinite) [Move=Allow only administrators] (indefinite)) wikitext text/x-wiki This page contains editing, styling, and page structure guidelines to be used {{SITENAME}}. It is recommended all editors follow them to whatever extent is reasonable in given context. The guidelines are subject to change. == Template use == Mark pages requiring visual / stylistic / tonal cleanup with [[Template:Cleanup]]. Mark pages / sections / other items missing crucial information with [[Template:todo]]. == Page structure == === Tool pages === Put installation remarks and instructions under a <code>== Installation ==</code> section. Put usage remarks and instructions under a <code>== Usage ==</code> section. == Misc == Put text that must be read exactly by the user (file paths, class/method names, string literals etc) in <code><nowiki><code> </code></nowiki></code> tags if it is inline, <code><nowiki><pre> </pre></nowiki></code> if it is multiline (unless it is otherwise clearly separated, i.e. being the sole thing occupying a table cell). 1234b807d8a47879eef54a77897f75ddb77881d3 255 251 2022-08-18T09:41:18Z Thalber 3 wikitext text/x-wiki This page contains editing, styling, and page structure guidelines to be used {{SITENAME}}. It is recommended all editors follow them to whatever extent is reasonable in given context. The guidelines are subject to change. For running task list, consult [https://trello.com/b/uajv3uYM/to-miraheze our trello board] (view-only link). To join as board member, find us on [https://discord.gg/rainworld RW Discord server] in <nowiki><#1005072570053316708></nowiki>. == Template use == Mark pages requiring visual / stylistic / tonal cleanup with [[Template:Cleanup]]. Mark pages / sections / other items missing crucial information with [[Template:todo]]. == Page structure == === Tool pages === Put installation remarks and instructions under a <code>== Installation ==</code> section. Put usage remarks and instructions under a <code>== Usage ==</code> section. == Misc == Put text that must be read exactly by the user (file paths, class/method names, string literals etc) in <code><nowiki><code> </code></nowiki></code> tags if it is inline, <code><nowiki><pre> </pre></nowiki></code> if it is multiline (unless it is otherwise clearly separated, i.e. being the sole thing occupying a table cell). 9efe0a68757112e22cab5d38e74bcd7283b25b5a Main Page 0 1 252 220 2022-08-18T09:16:47Z Thalber 3 wikitext text/x-wiki __NOTOC__ [[File:RWModdingTitle.png|800px|frameless|center]] <br> <div id="intro-text" style="text-align: center;"> '''Welcome!''' The Rain World Modding Wiki is a place to share information about modding the video game, ''Rain World''. For more about the game, check out the '''[https://rainworld.miraheze.org/wiki/Rain_World_Wiki Official Rain World Wiki]'''! This wiki is currently in the process of being ported from an old wiki. To get involved, be sure to check out the modding category in the [https://discord.gg/rainworld Rain World Discord]. </div> == Where to Start... == For instructions for installing mods, see [[Installing Mods]]. On a technical level, mods can be split into the following families: * [[:Category:Code Mods|Code Mods]] (any mod where the main component is a .dll file) * [[:Category:Content Mods|Content Mods]] (this includes region packs, arenas, etc.). Follow one of the links above to learn more about making these kinds of mods. Sometimes there is overlap. For example a [[Custom Region Support|region pack]] (a type of content mod) may require additional code mods for custom creatures, or a code mod may require additional asset files (though often they are embedded within the dll). If you have questions that the wiki can't yet answer, feel free to ask in the modding category in the [https://discord.gg/rainworld Rain World Discord]. == Contributing == If you have modding knowledge that the wiki doesn't yet have, please do contribute! The following categories contain pages demanding attention: * [[:Category:Cleanup needed]] * [[:Category:Unfinished]] Don't forget to check [[Contribution Guidelines]]. == Quick Links == * [[:Category:Code Mods]] * [[:Category:Content Mods]] * [[:Category:Dev Tools]] * [[:Category:Dependencies]] * [[:Category:Utility Mods]] * [[CRS]] * [[Warp]] f8640392ec2a8061b5fad52043dcf7323f10968a 271 252 2022-08-20T07:29:13Z Thalber 3 wikitext text/x-wiki __NOTOC__ [[File:RWModdingTitle.png|800px|frameless|center]] <br> <div id="intro-text" style="text-align: center;"> '''Welcome!''' The Rain World Modding Wiki is a place to share information about modding the video game, ''Rain World''. For more about the game, check out the '''[https://rainworld.miraheze.org/wiki/Rain_World_Wiki Official Rain World Wiki]'''! This wiki is currently in the process of being ported from an old wiki. To get involved, be sure to check out the modding category in the [https://discord.gg/rainworld Rain World Discord]. </div> == Where to Start... == For instructions for installing mods, see [[Installing Mods]]. Technical reference for Remix, the Parity+ built-in mod-loader, can be found [[Remix|here]]. On a technical level, mods can be split into the following families: * [[:Category:Code Mods|Code Mods]] (any mod where the main component is a .dll file) * [[:Category:Content Mods|Content Mods]] (this includes region packs, arenas, etc.). Follow one of the links above to learn more about making these kinds of mods. Sometimes there is overlap. For example a [[Custom Region Support|region pack]] (a type of content mod) may require additional code mods for custom creatures, or a code mod may require additional asset files (though often they are embedded within the dll). If you have questions that the wiki can't yet answer, feel free to ask in the modding category in the [https://discord.gg/rainworld Rain World Discord]. == Contributing == If you have modding knowledge that the wiki doesn't yet have, please do contribute! The following categories contain pages demanding attention: * [[:Category:Cleanup needed]] * [[:Category:Unfinished]] Don't forget to check [[Contribution Guidelines]]. == Quick Links == * [[:Category:Code Mods]] * [[:Category:Content Mods]] * [[:Category:Dev Tools]] * [[:Category:Dependencies]] * [[:Category:Utility Mods]] * [[CRS]] * [[Warp]] 7774cd677d34745d07c8927f26c39583a36c9a85 272 271 2022-08-20T07:42:19Z Thalber 3 wikitext text/x-wiki __NOTOC__ [[File:RWModdingTitle.png|800px|frameless|center]] <br> <div id="intro-text" style="text-align: center;"> '''Welcome!''' The Rain World Modding Wiki is a place to share information about modding the video game, ''Rain World''. For more about the game, check out the '''[https://rainworld.miraheze.org/wiki/Rain_World_Wiki Official Rain World Wiki]'''! This wiki is currently in the process of being ported from an old wiki. To get involved, be sure to check out the modding category in the [https://discord.gg/rainworld Rain World Discord]. </div> == Where to Start... == For instructions for installing mods, see [[Installing Mods]]. For description of architecture changes that will occur with release of Downpour, as well as technical reference for the incoming Remix built-in modloader, see [[Downpour Reference]]. On a technical level, mods can be split into the following families: * [[:Category:Code Mods|Code Mods]] (any mod where the main component is a .dll file) * [[:Category:Content Mods|Content Mods]] (this includes region packs, arenas, etc.). Follow one of the links above to learn more about making these kinds of mods. Sometimes there is overlap. For example a [[Custom Region Support|region pack]] (a type of content mod) may require additional code mods for custom creatures, or a code mod may require additional asset files (though often they are embedded within the dll). If you have questions that the wiki can't yet answer, feel free to ask in the modding category in the [https://discord.gg/rainworld Rain World Discord]. == Contributing == If you have modding knowledge that the wiki doesn't yet have, please do contribute! The following categories contain pages demanding attention: * [[:Category:Cleanup needed]] * [[:Category:Unfinished]] Don't forget to check [[Contribution Guidelines]]. == Quick Links == * [[:Category:Code Mods]] * [[:Category:Content Mods]] * [[:Category:Dev Tools]] * [[:Category:Dependencies]] * [[:Category:Utility Mods]] * [[CRS]] * [[Warp]] 27ea7f6551d90e6311392072c9c0c5a52b01261b ConfigMachine 0 115 253 231 2022-08-18T09:31:21Z Thalber 3 wikitext text/x-wiki '''Configmachine''' is a dependency mod that allows other mods to easily create in-game config GUI. It's currently shipped with [[BepInEx]] installation. == Features == === OptionInterface === This is the most common method of adding config screen to your mod. ==== Registering ==== '''OptionalUI.OptionInterface''' is the base class for option interfaces. <syntaxhighlight lang="csharp"> public class MyOI : OptionInterface { public MyOI() : base (plugin: MyPlugin.instance) // Your BaseUnityPlugin instance. Examples assume you have a static singleton instance of your mod. { } } </syntaxhighlight> Now add <code>LoadOI</code> static method in your <code>BaseUnityPlugin</code> class that returns your OptionInterface. <syntaxhighlight lang="c#"> public static OptionInterface LoadOI() => return new MyOI(); //set return type to "object" if you want your mod to be loaded even if CM is not. In that case, you will need to handle CM's absence on your own. </syntaxhighlight> ==== Designing GUI ==== For designing your GUI, using [https://inkscape.org/ Inkscape] is strongly suggested. With Inkscape, create a file with 600 x 600 pixel resolution, then enable [View] - [Canvas Orientation] - [Flip Vertically]. (Alternatively, you can use any CAD program which has up and right as positive axis by default) <!--The image below is a diagram of <code>Colorfoot</code>’s first <code>OpTab</code>.--> [[File:Colorfoot-GUI.png|thumb|right|alt=Colorfoot's GUI as an example|Colorfoot's GUI as an example]] All UIelements have bottom-left <code>pos</code>ition and rectangular <code>size</code>. (Some have <code>fixedSize</code> which you can see from the summary of their constructors). Think every element like rectangles, and arrange them as you need. (Circular UIelements have <code>rad</code> instead; You can consider them as a square with 2 * rad for its dimensions) [[File:Colorfoot-GUI0.png|thumb|none|alt=Example GUI Positioning|Example GUI Positioning]] For <code>pos</code> parameters, use the relative coordinate from bottom-left from the canvas to your item. For <code>size</code> parameters, use their size in pixel. If you’re using Inkscape with [Flip Vertically] setting on, you can get those from their properties without any calculation. [[File:Colorfoot-Inkscape.png|thumb|none|alt=Example GUI Inkscape|Example GUI in Inkscape]] Here are some tips for designing GUI: * If you have many things to display, organise them with categories and use <code>OpRect</code> to surround them. * You don’t have to put everything in a single <code>OpTab</code>. If the canvas gets crowded, disperse your items for easier readability. * Try to avoid using smaller <code>OpScrollBox</code>s to store many things in one place even if that’s an option: The users cannot see everything in a single screen which reduces usability greatly. ==== Initialization ==== <code>OptionInterface.Initialize</code> is called in IntroRoll(for loading configuration) and ConfigMenu (for displaying to users). You can check whether Initialize is called in ConfigMenu or not with <code>OptionInterface.isOptionMenu</code>. It usually goes like this following example: <syntaxhighlight lang="csharp"> public override void Initialize() { base.Initialize(); // This should be called before everything else Tabs = new OpTab[2]; // you can have up to 20 tabs Tabs[0] = new OpTab("Main"); // Each OpTab is 600 x 600 pixel sized canvas Tabs[1] = new OpTab("Second") { color = Color.cyan }; // You can change its button and canvas colour too // After Initializing Tabs, create UIelements and add them to tabs } </syntaxhighlight> Now initialize <code>UIelement</code>s and add them to <code>OpTab</code> (or <code>OpScrollBox</code>). The Z-order (the order in which they’re drawn) of <code>UIelement</code>s is the order of constructors, ''not'' the order they’re added to <code>OpTab</code>. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpLabel(100f, 500f, "My Text") { description = "This is My Text" }); // Any UIelement can have description, which will be shown // at the bottom of the screen when the mouse cursor is over it </syntaxhighlight> <code>UIconfig</code>s are a subcategory of <code>UIelement</code> which have <code>key</code> and <code>value</code> for storing user input values, both of them get saved automatically by Config Machine. Their constructor accepts <code>key</code> and <code>defaultValue</code> on top of everything else. <code>key</code> must be unique for all elements in your OI unless they are cosmetic. Setting the key to empty or anything that starts with <code>_</code> (underbar) will turn it <code>cosmetic</code>, and the value won’t be saved. Cosmetic UIconfig is useful when you want to have provided <code>UIconfig</code> for UI purpose but not for an actual configurable. (Similarly, ModID that starts with <code>_</code> will be completely ignored by Config Machine) <syntaxhighlight lang="csharp"> OpCheckBox chkExample = new OpCheckBox(260f, 360f, "Example", true); Tabs[0].AddItems(chkExample, new OpLabel(260f, 390f, "Enable Example") { bumpBehav = chkExample.bumpBehav }); // BumpBehaviour is Config Machine's custom class that allows smoothly animated reaction with the input // Setting OpLabel's bumpBehav to other UIconfig/UItrigger's bumpBehav allows it to highlight with that element </syntaxhighlight> <code>UItrigger</code>s are the other subcategory of <code>UIelement</code>s which have <code>signal</code>s. When the user activates an <code>UItrigger</code> in some way, it will call the <code>Signal</code> function in OptionInterface which will be explained later. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpSimpleButton(new Vector2(400f, 200f), new Vector2(100f, 24f), "press", "Press Me")); </syntaxhighlight> ==== Update ==== <code>Update</code> function is called every frame when the game is in ConfigMenu, and this OptionInterface is currently active (The user has currently selected this mod from the list on left). This is useful to make reactive GUI, especially since each <code>UIconfig</code> instance can have only one value saved. The following example code uses cosmetic <code>OpRadioButtonGroup</code> to have four <code>OpColorPicker</code>s in a single spot. <syntaxhighlight lang="csharp"> private OpRadioButtonGroup rbgSelect; private int select; private OpColorPicker[] cpkPlayers; public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; select = 0; rbgSelect = new OpRadioButtonGroup("_", select); Tabs[0].AddItems(rbgSelect); rbgSelect.SetButtons(new OpRadioButton[] { new OpRadioButton(50f, 100f){ description = "The Survivor"}, new OpRadioButton(100f, 100f){ description = "The Monk"}, new OpRadioButton(150f, 100f){ description = "The Hunter"}, new OpRadioButton(200f, 100f){ description = "The Nightcat"} } ); OpColorPicker[] cpkPlayers = new OpColorPicker[4]; for (int i = 0; i < 4; i++) { Tabs[0].AddItems(new OpLabel(50f * i, 70f, rbgSelect.buttons[i].description) { bumpBehav = rbgSelect.buttons[i].bumpBehav }); cpkPlayers[i] = new OpColorPicker(new Vector2(100f, 300f), $"Color{i}", "FFFFFF"); cpkPlayers[i].Hide(); } cpkPlayers[select].Show(); Tabs[0].AddItems(cpkPlayers); } public override void Update(float dt) { base.Update(dt); // dt is deltaTime if (select != rbgSelect.valueInt) { for (int i = 0; i < cpkPlayers.Length; i++) { cpkPlayers[i].Hide(); } select = rbgSelect.valueInt; cpkPlayers[select].Show(); } } </syntaxhighlight> ==== ConfigOnChange ==== <code>ConfigOnChange</code> is called whenever <code>config</code> Dictionary is updated, mainly when Config Machine loads OptionInterfaces in IntroRoll, and when the user saves changes of configuration in ConfigMenu. Override this method to grab your configurable values. <code>config</code> Dictionary is where <code>UIconfig</code>’s value is stored. The following is an example of how to convert a string value to the corresponding type. <syntaxhighlight lang="csharp">public override void ConfigOnChange() { base.ConfigOnChange(); MyMod.config.myInt = int.Parse(config["keyInt"]); MyMod.config.myFloat = float.Parse(config["keyFloat"]); MyMod.config.myKey = OpKeyBinder.StringToKeyCode(config["keyKey"]); MyMod.config.myColor = OpColorPicker.HexToColor(config["keyColor"]); } </syntaxhighlight> ==== Signal ==== <code>Signal</code> is called when the user has interacted with <code>UItrigger</code>. Override this to have your OI to react. <syntaxhighlight lang="csharp"> public override void Signal(UItrigger trigger, string signal) { switch (signal) { case "reset": ConfigMenu.ResetCurrentConfig(); // This is the same as pressing Reset Config Button. break; } } </syntaxhighlight> === Generated OIs === <code>GeneratedOI</code> is a child class of <code>OptionInterface</code> that helps generating fixed-format GUI with less effort. <span id="displaying-basic-profile"></span> ==== Displaying Basic Profile ==== Simply inheriting <code>GeneratedOI</code> instead of <code>OptionInterface</code> works. This does make your mod dependent to Config Machine, and Config Machine generates GUI to display the basic information of your mod without this dependency. So this is only useful when you’re using OptionInterface for other features, like its Translation API. <syntaxhighlight lang="c#"> public class MyOI : GeneratedOI { private const string desc = "Changes this thing and that thing"; public MyOI() : base(plugin: MyPlugin.instance, desc) { transFile = "MyPlugin.Translation.txt"; } } </syntaxhighlight> The code above would generate a GUI like the following image: [[File:GeneratedOI-sample.png|thumb|none|alt=GeneratedOI Sample|GeneratedOI Sample]] You can also use its static method <code>AddBasicProfile</code> for basic profiles on top of the canvas. This also has an overload that accepts <code>OpScrollBox</code> instead of <code>OpTab</code>, if you have <code>OpScrollBox</code> replacing <code>OpTab</code>. <syntaxhighlight lang="c#"> public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; GeneratedOI.AddBasicProfile(Tabs[0], rwMod); Tabs[0].AddItems(new OpCheckBox(100f, 350f, "EnableStuff", false) { description = "Enables this stuff" }); } </syntaxhighlight> ==== BepInEx.Configuration ==== If you don't provide an OptionInterface, BepInEx can generate a simple config screen from your [[BepInPlugins|plugin]]'s config bindings (see <code>BepInEx.Configuration</code>). If this happens, CM will not create a separate file to store your config values. This method has upsides and downsides. * You don’t need to reference Config Machine in your project, and this doesn’t create a dependency for Config Machine. * The users can configure the plugin by opening the cfg file in Notepad outside the game. * However, you do not have control on detailed GUI design. First, we need <code>ConfigEntry</code> which you can bind to the <code>Config</code> property of <code>BaseUnityPlugin</code>. Consult [https://docs.bepinex.dev/articles/dev_guide/plugin_tutorial/4_configuration.html BepInEx Documentation] for farther detail. <syntaxhighlight lang="c#"> public static ConfigEntry<string> cfgText; public static ConfigEntry<bool> cfgCheck; void Awake() { cfgText = Config.Bind( "General", // section: defines which OpTab this will go "My Setting", // key: the name of setting "Hello, world!" // defaultValue "This is a description. It does things." // The description will be shown the right side of UIconfig // When you hover your mouse on UIconfig, // the first sentence will be displayed at the bottom of the screen ); cfgCheck = Config.Bind("General", "My Other Setting", true, "Another description is this."); } </syntaxhighlight> To access those settings, use <code>Value</code>. <syntaxhighlight lang="c#"> if (cfgCheck.Value) { Logger.LogMessage(cfgText.Value); } </syntaxhighlight> === Translation Support === While you can support translation for your mod on your own, Config Machine also offers translation solution. ==== Preparation ==== <code>OptionInterface</code> has a method called <code>Translate</code>, and when it's initially called, it will load specified (<code>transFile</code>) txt file from your assembly and make Dictionary depending on Rain World's language setting. In <code>BaseUnityPlugin.LoadOI</code> method, store the <code>OptionInterface</code> instance in somewhere before returning it. <syntaxhighlight lang="c#"> public static MyOI oi; public static MyOI LoadOI() { oi = new MyOI(); return oi; } </syntaxhighlight> Then make a static method that calls the translation method. <syntaxhighlight lang="c#">public static string Translate(string orig) { if (oi != null) { return oi.Translate(orig); } return orig; } </syntaxhighlight> Now when you need to translate something, you can pass your string through this method. ==== Writing Translation txt ==== Create a txt file that contains translation, too. Add txt file to your project, ''make sure'' that its encoding is <code>UTF-8</code>, then set it to be [Embedded Resources] for its compile setting. Then, in the constructor of your OptionInterface, set <code>transFile</code> to that resource name. If you have not put it in any folder, it's usually <code>&lt;ProjectName&gt;.&lt;TxtFileName&gt;.txt</code>, but you might get it wrong. If it's wrong when <code>OptionInterface.Translate</code> is initially called, Config Machine will log all the resources in your assembly in exceptionLog.txt so you can copy from it. <syntaxhighlight lang="c#"> public MyOI() : base(plugin: MyPlugin.instance) { this.transFile = "MyPlugin.Translation.txt"; // if you do not know the resource name, just call Translate. // ConfigMachine will log all the resources in your assembly in exceptionLog.txt. } </syntaxhighlight> The format of the translation txt file for Config Machine is quite primitive. First, you add a keyword, then <code>|</code> for language separator, then language ID (<code>eng, ita, ger, spa, por, kor, jap, rus)</code>), <code>$</code> for another separator, then translation. If there is no translation, the translator will return the keyword, unless there is a translation for <code>eng</code>. (In that case, English "translation" will be used as default translation) The following is formatting example for txt file. <!-- corrupted korean samples have been replaced with russian, sorry folks ~~thalber --> <pre> // If the first two characters are '//', this line will be ignored. Nightcat Horn Colour|rus$Цвет рога // If you have variables, avoid using partial sentences. Not every language has the same subject-verb-object order. Press &lt;ThrowKey&gt; to stab.|rus$Нажмите &lt;ThrowKey&gt; для атаки. // When translating the shorter-phrase, the translation might be sensitive with context, but English one does not. Duplicate key causes error(You can check exceptionLog.txt for duplicates), so you can set 'eng' translation for these cases. Property_as of possession|eng$Property|rus$Собственность Property_as of quality|eng$Property|rus$Свойство // For line-breaks, use \n. (In code, it'd be \\n) Each line represents a phrase, so you can't use actual line-break in a single chunk. LINE\nBREAK|rus$ПЕРЕНОС\nСТРОКИ</pre> ==== Running Translation ==== And here are some examples in code. Yes, running every text through the <code>Translate</code> method is tedious, but this is usually how it's done in Rain World or many other games. Make sure to check your mod in another language to confirm you haven’t missed any item. <syntaxhighlight lang="c#"> labelCpkrRadio.text = MyPlugin.Translate("Nightcat Horn Colour"); instance.room.game.cameras[0].hud.textPrompt.AddMessage(MyPlugin.Translate("Press <ThrowKey> to stab.").Replace("<ThrowKey>", k.ToString())); // k is variable in this example. labelLineBreak.text = MyPlugin.Translate("LINE\\nBREAK"); </syntaxhighlight> <!-- These aren't the part of tutorial but more of tips. This does not just apply for making Rain World mods but to general, whenever you're making something that supports translation. * When you have variables in your sentence, do not use partial phrases and Frankenstein it later with <code>string.Concat</code>. Not every language has the same grammar order of subject-verb-object as English. * Leave credits to the translators, since you¡¯re most likely getting volunteers from them. This is both good for showing gratitude to the translators and keeping the quality of the translation. The lack of credits equals a lack of responsibility. * Do not use machine translation. That usually hurts the user experience rather than enhancing it. --> == Acceptable Types == As of Config Machine <code>v1.5.1</code>, it accepts the following types and uses provided UIconfig. (Height is the pixel height that how much this ConfigEntry would use. And each entry get 20 pixeled gaps in between) {|class="wikitable" !align="right" width="23%"| type !align="center" width="29%"| UIconfig !align="right" width="23%"| Height !width="23%"| Note |- |align="right"| bool |align="center"| OpCheckBox |align="right"| 60 | |- |align="right"| byte |align="center"| OpSliderSubtle |align="right"| 90 | Range: [0, 20] |- |align="right"| uint |align="center"| OpSlider |align="right"| 90 | Range: [0, 100] |- |align="right"| int |align="center"| OpTextBox |align="right"| 60 | Accepts: Int |- |align="right"| float |align="center"| OpTextBox |align="right"| 60 | Accepts: Float |- |align="right"| string(Hex) |align="center"| OpColorPicker |align="right"| 170 | When defaultValue is Hex |- |align="right"| string |align="center"| OpTextBox |align="right"| 60 | When defaultValue is not Hex; Accepts: ASCII |- |align="right"| KeyCode |align="center"| OpKeyBinder |align="right"| 100 | |- |align="right"| enumType |align="center"| OpResourceSelector |align="right"| 60 | |- |align="right"| default |align="center"| N/A |align="right"| | Will warn the user that this plugin has ConfigEntry that’s not supported by Config Machine |} == Available UI Elements == Full list of available UI elements can be found [[ConfigMachine/Provided Elements|here]]. [[Category:Dependencies]] [[Category:Code Mods]] b4474451ade144062e71851d30a98f9e9457b202 MonoMod Patches 0 107 254 158 2022-08-18T09:36:19Z Thalber 3 /* Usage */ wikitext text/x-wiki {{Cleanup}} '''MonoModPatches''' or '''MMPatches''' are one of the simplest ways of modifying vanilla code. They can be used with current version of our [[BepInEx]] package. MonoMod's [https://github.com/MonoMod/MonoMod/blob/master/README.md README] contains a description of this method. Short summary and RW-specific aspects are presented below. == Creation == * Create a project referencing both <code>MonoMod.exe</code> and <code>AssemblyCSharp.dll</code> * Create a type deriving from target class * Mark your class for patching. This can be done in two ways: *# Place your class in the exact same namespace and name it <code>patch_OriginalNamehere</code> (<code>patch_Player</code> to patch <code>Player</code>) *# Denote your class with <code>MonoModPatch</code> attribute like the following example <!--(<code>Custom</code>)--> <syntaxhighlight lang="csharp"> [MonoModPatch("global::Player")] //"global::" is the namespace for classes appearing "without a namespace" public class CustomPlayer : Player { } </syntaxhighlight> * For every method to patch, use the following pattern: <syntaxhighlight lang="csharp"> [MonoModPatch("global::Player")] public class CustomPlayer : Player { public extern void orig_Update(bool eu); public override void Update(bool eu) { //do your things orig_Update(eu); // original method body is inserted at the site of this call. Omit to not use original code at all (also disables layering MMPatches). //do your things } } </syntaxhighlight> To access a private member, create one with matching signature (type / name / params etc) and denote it with <code>MonoModIgnore</code> attribute. To patch a non-override public method, use <code>new</code> to hide the vanilla method for the compiler. === Things to note === * MMPatches should not be shipped in the same assembly as partmods/[[BepInPlugins]]. If that is done, there is only a small chance doing that will ''not'' turn your game into an firecracker plant. * <code>MonoModRules</code> described in MonoMod readme does not seem to coexist nicely with BepInEx. ''More testing is required to narrow down where things go terribly wrong.'' == Usage == MMPatches have to be named as following: <code>AssemblyCSharp.[modName].mm.dll</code>. They are loaded from <code>Rain World/BepInEx/monomod/</code> ''at preloader time''. [[BOI]] renames files automatically in a futile attempt to make the process more intuitive for the end user. [[Category:Code Mods]] a21a3a7ad7a1ca2180c0ac133e8807e711b4ec00 File:sloogo.png 6 140 256 2022-08-18T09:48:29Z Thalber 3 the legend wikitext text/x-wiki == Summary == the legend b49adb9a3e7a6016793fc22b545b9eb8b63224c7 UserWiki:Thalber 200 141 257 2022-08-18T09:52:09Z Thalber 3 Created page with "I buzz around every now and then." wikitext text/x-wiki I buzz around every now and then. 3da9a4f395436b0fd89fa69db37e4b288f96ef5c Template:!! 10 142 258 2022-08-18T10:33:37Z Thalber 3 Created page with "<includeonly> <nowiki>||</nowiki> </includeonly> <noinclude> == Usage == <nowiki> {{!!}} </nowiki> {{!!}} </noinclude>" wikitext text/x-wiki <includeonly> <nowiki>||</nowiki> </includeonly> <noinclude> == Usage == <nowiki> {{!!}} </nowiki> {{!!}} </noinclude> 0f9068ab85b9020f5afd9335f2c0abefa838a4d7 259 258 2022-08-18T10:34:08Z Thalber 3 wikitext text/x-wiki <includeonly>||</includeonly> <noinclude> == Usage == <nowiki> {{!!}} </nowiki> {{!!}} </noinclude> a3333fa5dd6f7286ff6230680c5d288ef0a7e11f Template:Toolinfo 10 143 260 2022-08-18T10:52:10Z Thalber 3 Created page with "<includeonly> {|class="infoboxtable" |- <!-- header --> ! colspan="2" class="infoboxname" | "{{{name}}}"<br>{{#if: {{{icon|}}} | [[File:{{{icon}}}]] | }} |- {{#if: {{{image|}}} | ! colspan="2" {{!}} [[File:{{{image}}}{{!}}{{{size|250x250px}}}]] | ! colspan="2" {{!}} ''No image yet''{{#ifeq: {{NAMESPACE}} | Template | | [[Category:Infoboxes lacking images]]}} }} |- ! colspan="2" class="infoboxdetails" | Details <!-- body --> |- {{#if: {{{type|}}} | {{!}} {{!}} <div>To..." wikitext text/x-wiki <includeonly> {|class="infoboxtable" |- <!-- header --> ! colspan="2" class="infoboxname" | "{{{name}}}"<br>{{#if: {{{icon|}}} | [[File:{{{icon}}}]] | }} |- {{#if: {{{image|}}} | ! colspan="2" {{!}} [[File:{{{image}}}{{!}}{{{size|250x250px}}}]] | ! colspan="2" {{!}} ''No image yet''{{#ifeq: {{NAMESPACE}} | Template | | [[Category:Infoboxes lacking images]]}} }} |- ! colspan="2" class="infoboxdetails" | Details <!-- body --> |- {{#if: {{{type|}}} | {{!}} {{!}} <div>Tool type</div> {{!!}} {{{type}}} }} |- {{#if: {{{license|}}} | {{!}} <div>License</div> {{!!}} {{{license}}} }} |- {{#if: {{{authors|}}} | {{!}} <div>Authors</div> {{!!}} {{{authors}}} }} |- {{#if: {{{maintainers|}}} | {{!}} <div>Maintainers</div> {{!!}} {{{maintainers}}} }} |- {{#if: {{{status|}}} | {{!}} <div>Status</div> {{!!}} {{{status}}} }} |- {{#if: {{{releases|}}} | {{!}} <div>Release links</div> {{!!}} {{{releases}}} }} |- <!-- {{#if: {{{difficulties|}}} | {{!}} <div>Exclusive Difficulty</div> {{!!}} {{{difficulties}}} }} |- {{#if: {{{respawn|}}} | {{!}} <div>Respawn Time</div> {{!!}} {{{respawn}}} }} {{#if: {{{explosive|}}}{{{bite|}}}{{{head|}}}{{{headexplosive|}}}{{{headbite|}}}{{{throat|}}}{{{throatexplosive|}}}{{{throatbite|}}}{{{stuckspear|}}}{{{headstuckspear|}}}{{{shell|}}} | {{!}}- {{!}} colspan="2" {{!}} {{{!}} style="width:100%;" class="mw-collapsible mw-collapsed" data-expandtext=" ↓ " data-collapsetext=" ↑ " cellspacing=0 {{!}}- !colspan="2" style="background-color:#012d59;color:#FFFFFF;border-radius:8px; text-align:center; padding-left:22px;" {{!}} Damage Multipliers {{!}}- {{#if: {{{explosive|}}} | {{!}} '''Explosive''' {{!}} {{{explosive}}}}} {{!}}- {{#if: {{{bite|}}} | {{!}} '''Bite''' {{!}} {{{bite}}}}} {{!}}- {{#if: {{{head|}}} | {{!}} '''Head''' {{!}} {{{head}}}}} {{!}}- {{#if: {{{headexplosive|}}} | {{!}} '''Head (Explosive)''' {{!}} {{{headexplosive}}}}} {{!}}- {{#if: {{{headbite|}}} | {{!}} '''Head (Bite)''' {{!}} {{{headbite}}}}} {{!}}- {{#if: {{{throat|}}} | {{!}} '''Throat''' {{!}} {{{throat}}}}} {{!}}- {{#if: {{{throatexplosive|}}} | {{!}} '''Throat (Explosive)''' {{!}} {{{throatexplosive}}}}} {{!}}- {{#if: {{{throatbite|}}} | {{!}} '''Throat (Bite)''' {{!}} {{{throatbite}}}}} {{!}}- {{#if: {{{stuckspear|}}} | {{!}} '''Any segment (With embedded spear)''' {{!}} {{{stuckspear}}}}} {{!}}- {{#if: {{{headstuckspear|}}} | {{!}} '''Head (With embedded spear)''' {{!}} {{{headstuckspear}}}}} {{!}}- {{#if: {{{shell|}}} | {{!}} '''Shell''' {{!}} {{{shell}}}}} {{!}}} }} --> |} </includeonly> <noinclude> == Usage == {{Toolinfo |name=thing |icon=hunterAngy.png |image=sloogo.png |type=Sacred item |authors=The gods from beyond |maintainers=Gar |status=Eternal |releases=[https://github.com/DryCryCrystal/Region-Kit/releases GitHub (obviously)] }} <pre> {{Toolinfo |name=thing |noicon=yes |image=sloogo.png |type=Sacred item |authors=The gods from beyond |maintainers=Gar |status=Eternal |releases=[https://github.com/DryCryCrystal/Region-Kit/releases GitHub (obviously)] }} </pre> {| class="wikitable" |+ Caption text |- ! Header text !! Header text !! Header text |- | Example || Example || Example |- | Example || Example || Example |- | Example || Example || Example |} {|class="wikitable" |+ Fields ! Field !! Meaning |- | name || Infobox title |- | icon || icon image to be used |- | image || image to be used |- | type || Tool type (external program, script, macro etc) |- | authors || Parties involved in creation of the tool or its parts |- | maintainers || Parties persistently maintaining the tool |- | status || Support status of tool (Active development, LTS, Abandoned etc) |} </noinclude> d95ccdb4ad4220bd2063be2236a3ba6b7f3c65d6 261 260 2022-08-18T10:53:05Z Thalber 3 wikitext text/x-wiki <includeonly> {|class="infoboxtable" |- <!-- header --> ! colspan="2" class="infoboxname" | "{{{name}}}"<br>{{#if: {{{icon|}}} | [[File:{{{icon}}}]] | }} |- {{#if: {{{image|}}} | ! colspan="2" {{!}} [[File:{{{image}}}{{!}}{{{size|250x250px}}}]] | ! colspan="2" {{!}} ''No image yet''{{#ifeq: {{NAMESPACE}} | Template | | [[Category:Infoboxes lacking images]]}} }} |- ! colspan="2" class="infoboxdetails" | Details <!-- body --> |- {{#if: {{{type|}}} | {{!}} {{!}} <div>Tool type</div> {{!!}} {{{type}}} }} |- {{#if: {{{license|}}} | {{!}} <div>License</div> {{!!}} {{{license}}} }} |- {{#if: {{{authors|}}} | {{!}} <div>Authors</div> {{!!}} {{{authors}}} }} |- {{#if: {{{maintainers|}}} | {{!}} <div>Maintainers</div> {{!!}} {{{maintainers}}} }} |- {{#if: {{{status|}}} | {{!}} <div>Status</div> {{!!}} {{{status}}} }} |- {{#if: {{{releases|}}} | {{!}} <div>Release links</div> {{!!}} {{{releases}}} }} |- <!-- {{#if: {{{difficulties|}}} | {{!}} <div>Exclusive Difficulty</div> {{!!}} {{{difficulties}}} }} |- {{#if: {{{respawn|}}} | {{!}} <div>Respawn Time</div> {{!!}} {{{respawn}}} }} {{#if: {{{explosive|}}}{{{bite|}}}{{{head|}}}{{{headexplosive|}}}{{{headbite|}}}{{{throat|}}}{{{throatexplosive|}}}{{{throatbite|}}}{{{stuckspear|}}}{{{headstuckspear|}}}{{{shell|}}} | {{!}}- {{!}} colspan="2" {{!}} {{{!}} style="width:100%;" class="mw-collapsible mw-collapsed" data-expandtext=" ↓ " data-collapsetext=" ↑ " cellspacing=0 {{!}}- !colspan="2" style="background-color:#012d59;color:#FFFFFF;border-radius:8px; text-align:center; padding-left:22px;" {{!}} Damage Multipliers {{!}}- {{#if: {{{explosive|}}} | {{!}} '''Explosive''' {{!}} {{{explosive}}}}} {{!}}- {{#if: {{{bite|}}} | {{!}} '''Bite''' {{!}} {{{bite}}}}} {{!}}- {{#if: {{{head|}}} | {{!}} '''Head''' {{!}} {{{head}}}}} {{!}}- {{#if: {{{headexplosive|}}} | {{!}} '''Head (Explosive)''' {{!}} {{{headexplosive}}}}} {{!}}- {{#if: {{{headbite|}}} | {{!}} '''Head (Bite)''' {{!}} {{{headbite}}}}} {{!}}- {{#if: {{{throat|}}} | {{!}} '''Throat''' {{!}} {{{throat}}}}} {{!}}- {{#if: {{{throatexplosive|}}} | {{!}} '''Throat (Explosive)''' {{!}} {{{throatexplosive}}}}} {{!}}- {{#if: {{{throatbite|}}} | {{!}} '''Throat (Bite)''' {{!}} {{{throatbite}}}}} {{!}}- {{#if: {{{stuckspear|}}} | {{!}} '''Any segment (With embedded spear)''' {{!}} {{{stuckspear}}}}} {{!}}- {{#if: {{{headstuckspear|}}} | {{!}} '''Head (With embedded spear)''' {{!}} {{{headstuckspear}}}}} {{!}}- {{#if: {{{shell|}}} | {{!}} '''Shell''' {{!}} {{{shell}}}}} {{!}}} }} --> |} </includeonly> <noinclude> == Usage == {{Toolinfo |name=thing |icon=hunterAngy.png |image=sloogo.png |type=Sacred item |authors=The gods from beyond |maintainers=Gar |status=Eternal |releases=[https://github.com/DryCryCrystal/Region-Kit/releases GitHub (obviously)] }} <pre> {{Toolinfo |name=thing |noicon=yes |image=sloogo.png |type=Sacred item |authors=The gods from beyond |maintainers=Gar |status=Eternal |releases=[https://github.com/DryCryCrystal/Region-Kit/releases GitHub (obviously)] }} </pre> {|class="wikitable" |+ Fields ! Field !! Meaning |- | name || Infobox title |- | icon || icon image to be used |- | image || image to be used |- | type || Tool type (external program, script, macro etc) |- | authors || Parties involved in creation of the tool or its parts |- | maintainers || Parties persistently maintaining the tool |- | status || Support status of tool (Active development, LTS, Abandoned etc) |} </noinclude> <!-- stolen code from big sister to be removed ~~th --> 767059ff013471f76f893ee10e475666b1fb5e04 262 261 2022-08-18T11:24:48Z Thalber 3 wikitext text/x-wiki <includeonly> {|class="infoboxtable" |- <!-- header --> ! colspan="2" class="infoboxname" | "{{{name}}}"<br>{{#if: {{{icon|}}} | [[File:{{{icon}}}]] | }} |- {{#if: {{{image|}}} | ! colspan="2" {{!}} [[File:{{{image}}}{{!}}{{{size|250x250px}}}]] | ! colspan="2" {{!}} ''No image yet''<!--{{#ifeq: {{NAMESPACE}} | Template | | [[Category:Infoboxes lacking images]]}} -->}} |- ! colspan="2" class="infoboxdetails" | Details <!-- body --> |- {{#if: {{{type|}}} | {{!}} {{!}} <div>Tool type</div> {{!!}} {{{type}}} }} |- {{#if: {{{license|}}} | {{!}} <div>License</div> {{!!}} {{{license}}} }} |- {{#if: {{{authors|}}} | {{!}} <div>Authors</div> {{!!}} {{{authors}}} }} |- {{#if: {{{maintainers|}}} | {{!}} <div>Maintainers</div> {{!!}} {{{maintainers}}} }} |- {{#if: {{{status|}}} | {{!}} <div>Status</div> {{!!}} {{{status}}} }} |- {{#if: {{{releases|}}} | {{!}} <div>Release links</div> {{!!}} {{{releases}}} }} |- <!-- {{#if: {{{difficulties|}}} | {{!}} <div>Exclusive Difficulty</div> {{!!}} {{{difficulties}}} }} |- {{#if: {{{respawn|}}} | {{!}} <div>Respawn Time</div> {{!!}} {{{respawn}}} }} {{#if: {{{explosive|}}}{{{bite|}}}{{{head|}}}{{{headexplosive|}}}{{{headbite|}}}{{{throat|}}}{{{throatexplosive|}}}{{{throatbite|}}}{{{stuckspear|}}}{{{headstuckspear|}}}{{{shell|}}} | {{!}}- {{!}} colspan="2" {{!}} {{{!}} style="width:100%;" class="mw-collapsible mw-collapsed" data-expandtext=" ↓ " data-collapsetext=" ↑ " cellspacing=0 {{!}}- !colspan="2" style="background-color:#012d59;color:#FFFFFF;border-radius:8px; text-align:center; padding-left:22px;" {{!}} Damage Multipliers {{!}}- {{#if: {{{explosive|}}} | {{!}} '''Explosive''' {{!}} {{{explosive}}}}} {{!}}- {{#if: {{{bite|}}} | {{!}} '''Bite''' {{!}} {{{bite}}}}} {{!}}- {{#if: {{{head|}}} | {{!}} '''Head''' {{!}} {{{head}}}}} {{!}}- {{#if: {{{headexplosive|}}} | {{!}} '''Head (Explosive)''' {{!}} {{{headexplosive}}}}} {{!}}- {{#if: {{{headbite|}}} | {{!}} '''Head (Bite)''' {{!}} {{{headbite}}}}} {{!}}- {{#if: {{{throat|}}} | {{!}} '''Throat''' {{!}} {{{throat}}}}} {{!}}- {{#if: {{{throatexplosive|}}} | {{!}} '''Throat (Explosive)''' {{!}} {{{throatexplosive}}}}} {{!}}- {{#if: {{{throatbite|}}} | {{!}} '''Throat (Bite)''' {{!}} {{{throatbite}}}}} {{!}}- {{#if: {{{stuckspear|}}} | {{!}} '''Any segment (With embedded spear)''' {{!}} {{{stuckspear}}}}} {{!}}- {{#if: {{{headstuckspear|}}} | {{!}} '''Head (With embedded spear)''' {{!}} {{{headstuckspear}}}}} {{!}}- {{#if: {{{shell|}}} | {{!}} '''Shell''' {{!}} {{{shell}}}}} {{!}}} }} --> |} </includeonly> <noinclude> == Usage == {{Toolinfo |name=thing |icon=hunterAngy.png |image=sloogo.png |type=Sacred item |authors=The gods from beyond |maintainers=Gar |status=Eternal |releases=[https://github.com/DryCryCrystal/Region-Kit/releases GitHub (obviously)] }} <pre> {{Toolinfo |name=thing |noicon=yes |image=sloogo.png |type=Sacred item |authors=The gods from beyond |maintainers=Gar |status=Eternal |releases=[https://github.com/DryCryCrystal/Region-Kit/releases GitHub (obviously)] }} </pre> {|class="wikitable" |+ Fields ! Field !! Meaning |- | name || Infobox title |- | icon || icon image to be used |- | image || image to be used |- | type || Tool type (external program, script, macro etc) |- | authors || Parties involved in creation of the tool or its parts |- | maintainers || Parties persistently maintaining the tool |- | status || Support status of tool (Active development, LTS, Abandoned etc) |} </noinclude> <!-- stolen code from big sister to be removed ~~th --> 17fbf701ea673e7789a38c045234ae8a0fe7e361 263 262 2022-08-18T11:25:14Z Thalber 3 wikitext text/x-wiki <includeonly> {|class="infoboxtable" |- <!-- header --> ! colspan="2" class="infoboxname" | "{{{name}}}"<br>{{#if: {{{icon|}}} | [[File:{{{icon}}}]] | }} |- {{#if: {{{image|}}} | ! colspan="2" {{!}} [[File:{{{image}}}{{!}}{{{size|250x250px}}}]] | ! colspan="2" {{!}} ''No image''<!--{{#ifeq: {{NAMESPACE}} | Template | | [[Category:Infoboxes lacking images]]}} -->}} |- ! colspan="2" class="infoboxdetails" | Details <!-- body --> |- {{#if: {{{type|}}} | {{!}} {{!}} <div>Tool type</div> {{!!}} {{{type}}} }} |- {{#if: {{{license|}}} | {{!}} <div>License</div> {{!!}} {{{license}}} }} |- {{#if: {{{authors|}}} | {{!}} <div>Authors</div> {{!!}} {{{authors}}} }} |- {{#if: {{{maintainers|}}} | {{!}} <div>Maintainers</div> {{!!}} {{{maintainers}}} }} |- {{#if: {{{status|}}} | {{!}} <div>Status</div> {{!!}} {{{status}}} }} |- {{#if: {{{releases|}}} | {{!}} <div>Release links</div> {{!!}} {{{releases}}} }} |- <!-- {{#if: {{{difficulties|}}} | {{!}} <div>Exclusive Difficulty</div> {{!!}} {{{difficulties}}} }} |- {{#if: {{{respawn|}}} | {{!}} <div>Respawn Time</div> {{!!}} {{{respawn}}} }} {{#if: {{{explosive|}}}{{{bite|}}}{{{head|}}}{{{headexplosive|}}}{{{headbite|}}}{{{throat|}}}{{{throatexplosive|}}}{{{throatbite|}}}{{{stuckspear|}}}{{{headstuckspear|}}}{{{shell|}}} | {{!}}- {{!}} colspan="2" {{!}} {{{!}} style="width:100%;" class="mw-collapsible mw-collapsed" data-expandtext=" ↓ " data-collapsetext=" ↑ " cellspacing=0 {{!}}- !colspan="2" style="background-color:#012d59;color:#FFFFFF;border-radius:8px; text-align:center; padding-left:22px;" {{!}} Damage Multipliers {{!}}- {{#if: {{{explosive|}}} | {{!}} '''Explosive''' {{!}} {{{explosive}}}}} {{!}}- {{#if: {{{bite|}}} | {{!}} '''Bite''' {{!}} {{{bite}}}}} {{!}}- {{#if: {{{head|}}} | {{!}} '''Head''' {{!}} {{{head}}}}} {{!}}- {{#if: {{{headexplosive|}}} | {{!}} '''Head (Explosive)''' {{!}} {{{headexplosive}}}}} {{!}}- {{#if: {{{headbite|}}} | {{!}} '''Head (Bite)''' {{!}} {{{headbite}}}}} {{!}}- {{#if: {{{throat|}}} | {{!}} '''Throat''' {{!}} {{{throat}}}}} {{!}}- {{#if: {{{throatexplosive|}}} | {{!}} '''Throat (Explosive)''' {{!}} {{{throatexplosive}}}}} {{!}}- {{#if: {{{throatbite|}}} | {{!}} '''Throat (Bite)''' {{!}} {{{throatbite}}}}} {{!}}- {{#if: {{{stuckspear|}}} | {{!}} '''Any segment (With embedded spear)''' {{!}} {{{stuckspear}}}}} {{!}}- {{#if: {{{headstuckspear|}}} | {{!}} '''Head (With embedded spear)''' {{!}} {{{headstuckspear}}}}} {{!}}- {{#if: {{{shell|}}} | {{!}} '''Shell''' {{!}} {{{shell}}}}} {{!}}} }} --> |} </includeonly> <noinclude> == Usage == {{Toolinfo |name=thing |icon=hunterAngy.png |image=sloogo.png |type=Sacred item |authors=The gods from beyond |maintainers=Gar |status=Eternal |releases=[https://github.com/DryCryCrystal/Region-Kit/releases GitHub (obviously)] }} <pre> {{Toolinfo |name=thing |noicon=yes |image=sloogo.png |type=Sacred item |authors=The gods from beyond |maintainers=Gar |status=Eternal |releases=[https://github.com/DryCryCrystal/Region-Kit/releases GitHub (obviously)] }} </pre> {|class="wikitable" |+ Fields ! Field !! Meaning |- | name || Infobox title |- | icon || icon image to be used |- | image || image to be used |- | type || Tool type (external program, script, macro etc) |- | authors || Parties involved in creation of the tool or its parts |- | maintainers || Parties persistently maintaining the tool |- | status || Support status of tool (Active development, LTS, Abandoned etc) |} </noinclude> <!-- stolen code from big sister to be removed ~~th --> 0db592257feca2f8b3b82bbf2dbe7206253762cb 265 263 2022-08-18T11:29:55Z Thalber 3 wikitext text/x-wiki <includeonly> {|class="infoboxtable" |- <!-- header --> ! colspan="2" class="infoboxname" | "{{{name|{{PAGENAME}} }}}"<br>{{#if: {{{icon|}}} | [[File:{{{icon}}}]] | }} |- {{#if: {{{image|}}} | ! colspan="2" {{!}} [[File:{{{image}}}{{!}}{{{size|250x250px}}}]] | ! colspan="2" {{!}} ''No image''<!--{{#ifeq: {{NAMESPACE}} | Template | | [[Category:Infoboxes lacking images]]}} -->}} |- ! colspan="2" class="infoboxdetails" | Details <!-- body --> |- {{#if: {{{type|}}} | {{!}} {{!}} <div>Tool type</div> {{!!}} {{{type}}} }} |- {{#if: {{{license|}}} | {{!}} <div>License</div> {{!!}} {{{license}}} }} |- {{#if: {{{authors|}}} | {{!}} <div>Authors</div> {{!!}} {{{authors}}} }} |- {{#if: {{{maintainers|}}} | {{!}} <div>Maintainers</div> {{!!}} {{{maintainers}}} }} |- {{#if: {{{status|}}} | {{!}} <div>Status</div> {{!!}} {{{status}}} }} |- {{#if: {{{releases|}}} | {{!}} <div>Release links</div> {{!!}} {{{releases}}} }} |- <!-- {{#if: {{{difficulties|}}} | {{!}} <div>Exclusive Difficulty</div> {{!!}} {{{difficulties}}} }} |- {{#if: {{{respawn|}}} | {{!}} <div>Respawn Time</div> {{!!}} {{{respawn}}} }} {{#if: {{{explosive|}}}{{{bite|}}}{{{head|}}}{{{headexplosive|}}}{{{headbite|}}}{{{throat|}}}{{{throatexplosive|}}}{{{throatbite|}}}{{{stuckspear|}}}{{{headstuckspear|}}}{{{shell|}}} | {{!}}- {{!}} colspan="2" {{!}} {{{!}} style="width:100%;" class="mw-collapsible mw-collapsed" data-expandtext=" ↓ " data-collapsetext=" ↑ " cellspacing=0 {{!}}- !colspan="2" style="background-color:#012d59;color:#FFFFFF;border-radius:8px; text-align:center; padding-left:22px;" {{!}} Damage Multipliers {{!}}- {{#if: {{{explosive|}}} | {{!}} '''Explosive''' {{!}} {{{explosive}}}}} {{!}}- {{#if: {{{bite|}}} | {{!}} '''Bite''' {{!}} {{{bite}}}}} {{!}}- {{#if: {{{head|}}} | {{!}} '''Head''' {{!}} {{{head}}}}} {{!}}- {{#if: {{{headexplosive|}}} | {{!}} '''Head (Explosive)''' {{!}} {{{headexplosive}}}}} {{!}}- {{#if: {{{headbite|}}} | {{!}} '''Head (Bite)''' {{!}} {{{headbite}}}}} {{!}}- {{#if: {{{throat|}}} | {{!}} '''Throat''' {{!}} {{{throat}}}}} {{!}}- {{#if: {{{throatexplosive|}}} | {{!}} '''Throat (Explosive)''' {{!}} {{{throatexplosive}}}}} {{!}}- {{#if: {{{throatbite|}}} | {{!}} '''Throat (Bite)''' {{!}} {{{throatbite}}}}} {{!}}- {{#if: {{{stuckspear|}}} | {{!}} '''Any segment (With embedded spear)''' {{!}} {{{stuckspear}}}}} {{!}}- {{#if: {{{headstuckspear|}}} | {{!}} '''Head (With embedded spear)''' {{!}} {{{headstuckspear}}}}} {{!}}- {{#if: {{{shell|}}} | {{!}} '''Shell''' {{!}} {{{shell}}}}} {{!}}} }} --> |} </includeonly> <noinclude> == Usage == {{Toolinfo |name=thing |icon=hunterAngy.png |image=sloogo.png |type=Sacred item |authors=The gods from beyond |maintainers=Gar |status=Eternal |releases=[https://github.com/DryCryCrystal/Region-Kit/releases GitHub (obviously)] }} <pre> {{Toolinfo |name=thing |noicon=yes |image=sloogo.png |type=Sacred item |authors=The gods from beyond |maintainers=Gar |status=Eternal |releases=[https://github.com/DryCryCrystal/Region-Kit/releases GitHub (obviously)] }} </pre> {|class="wikitable" |+ Fields ! Field !! Meaning |- | name || Infobox title |- | icon || icon image to be used |- | image || image to be used |- | type || Tool type (external program, script, macro etc) |- | authors || Parties involved in creation of the tool or its parts |- | maintainers || Parties persistently maintaining the tool |- | status || Support status of tool (Active development, LTS, Abandoned etc) |} </noinclude> <!-- stolen code from big sister to be removed ~~th --> c58dee997bb7765d66487e23abc2d74d939424f2 266 265 2022-08-18T11:30:43Z Thalber 3 wikitext text/x-wiki <includeonly> {|class="infoboxtable" |- <!-- header --> ! colspan="2" class="infoboxname" | "{{{name|{{PAGENAME}}}}}"<br>{{#if: {{{icon|}}} | [[File:{{{icon}}}]] | }} |- {{#if: {{{image|}}} | ! colspan="2" {{!}} [[File:{{{image}}}{{!}}{{{size|250x250px}}}]] | ! colspan="2" {{!}} ''No image''<!--{{#ifeq: {{NAMESPACE}} | Template | | [[Category:Infoboxes lacking images]]}} -->}} |- ! colspan="2" class="infoboxdetails" | Details <!-- body --> |- {{#if: {{{type|}}} | {{!}} {{!}} <div>Tool type</div> {{!!}} {{{type}}} }} |- {{#if: {{{license|}}} | {{!}} <div>License</div> {{!!}} {{{license}}} }} |- {{#if: {{{authors|}}} | {{!}} <div>Authors</div> {{!!}} {{{authors}}} }} |- {{#if: {{{maintainers|}}} | {{!}} <div>Maintainers</div> {{!!}} {{{maintainers}}} }} |- {{#if: {{{status|}}} | {{!}} <div>Status</div> {{!!}} {{{status}}} }} |- {{#if: {{{releases|}}} | {{!}} <div>Release links</div> {{!!}} {{{releases}}} }} |- <!-- {{#if: {{{difficulties|}}} | {{!}} <div>Exclusive Difficulty</div> {{!!}} {{{difficulties}}} }} |- {{#if: {{{respawn|}}} | {{!}} <div>Respawn Time</div> {{!!}} {{{respawn}}} }} {{#if: {{{explosive|}}}{{{bite|}}}{{{head|}}}{{{headexplosive|}}}{{{headbite|}}}{{{throat|}}}{{{throatexplosive|}}}{{{throatbite|}}}{{{stuckspear|}}}{{{headstuckspear|}}}{{{shell|}}} | {{!}}- {{!}} colspan="2" {{!}} {{{!}} style="width:100%;" class="mw-collapsible mw-collapsed" data-expandtext=" ↓ " data-collapsetext=" ↑ " cellspacing=0 {{!}}- !colspan="2" style="background-color:#012d59;color:#FFFFFF;border-radius:8px; text-align:center; padding-left:22px;" {{!}} Damage Multipliers {{!}}- {{#if: {{{explosive|}}} | {{!}} '''Explosive''' {{!}} {{{explosive}}}}} {{!}}- {{#if: {{{bite|}}} | {{!}} '''Bite''' {{!}} {{{bite}}}}} {{!}}- {{#if: {{{head|}}} | {{!}} '''Head''' {{!}} {{{head}}}}} {{!}}- {{#if: {{{headexplosive|}}} | {{!}} '''Head (Explosive)''' {{!}} {{{headexplosive}}}}} {{!}}- {{#if: {{{headbite|}}} | {{!}} '''Head (Bite)''' {{!}} {{{headbite}}}}} {{!}}- {{#if: {{{throat|}}} | {{!}} '''Throat''' {{!}} {{{throat}}}}} {{!}}- {{#if: {{{throatexplosive|}}} | {{!}} '''Throat (Explosive)''' {{!}} {{{throatexplosive}}}}} {{!}}- {{#if: {{{throatbite|}}} | {{!}} '''Throat (Bite)''' {{!}} {{{throatbite}}}}} {{!}}- {{#if: {{{stuckspear|}}} | {{!}} '''Any segment (With embedded spear)''' {{!}} {{{stuckspear}}}}} {{!}}- {{#if: {{{headstuckspear|}}} | {{!}} '''Head (With embedded spear)''' {{!}} {{{headstuckspear}}}}} {{!}}- {{#if: {{{shell|}}} | {{!}} '''Shell''' {{!}} {{{shell}}}}} {{!}}} }} --> |} </includeonly> <noinclude> == Usage == {{Toolinfo |name=thing |icon=hunterAngy.png |image=sloogo.png |type=Sacred item |authors=The gods from beyond |maintainers=Gar |status=Eternal |releases=[https://github.com/DryCryCrystal/Region-Kit/releases GitHub (obviously)] }} <pre> {{Toolinfo |name=thing |noicon=yes |image=sloogo.png |type=Sacred item |authors=The gods from beyond |maintainers=Gar |status=Eternal |releases=[https://github.com/DryCryCrystal/Region-Kit/releases GitHub (obviously)] }} </pre> {|class="wikitable" |+ Fields ! Field !! Meaning |- | name || Infobox title |- | icon || icon image to be used |- | image || image to be used |- | type || Tool type (external program, script, macro etc) |- | authors || Parties involved in creation of the tool or its parts |- | maintainers || Parties persistently maintaining the tool |- | status || Support status of tool (Active development, LTS, Abandoned etc) |} </noinclude> <!-- stolen code from big sister to be removed ~~th --> 7e4c2fc0d9d3a9663c4f2488437ddadc9f0a0cb7 291 266 2022-08-20T13:38:43Z Thalber 3 trim wikitext text/x-wiki <includeonly> {|class="infoboxtable" |- <!-- header --> ! colspan="2" class="infoboxname" | "{{{name|{{PAGENAME}}}}}"<br>{{#if: {{{icon|}}} | [[File:{{{icon}}}]] | }} |- {{#if: {{{image|}}} | ! colspan="2" {{!}} [[File:{{{image}}}{{!}}{{{size|250x250px}}}]] | ! colspan="2" {{!}} ''No image''<!--{{#ifeq: {{NAMESPACE}} | Template | | [[Category:Infoboxes lacking images]]}} -->}} |- ! colspan="2" class="infoboxdetails" | Details <!-- body --> |- {{#if: {{{type|}}} | {{!}} {{!}} <div>Tool type</div> {{!!}} {{{type}}} }} |- {{#if: {{{license|}}} | {{!}} <div>License</div> {{!!}} {{{license}}} }} |- {{#if: {{{authors|}}} | {{!}} <div>Authors</div> {{!!}} {{{authors}}} }} |- {{#if: {{{maintainers|}}} | {{!}} <div>Maintainers</div> {{!!}} {{{maintainers}}} }} |- {{#if: {{{status|}}} | {{!}} <div>Status</div> {{!!}} {{{status}}} }} |- {{#if: {{{releases|}}} | {{!}} <div>Release links</div> {{!!}} {{{releases}}} }} |- |} </includeonly> <noinclude> == Usage == {{Toolinfo |name=thing |icon=hunterAngy.png |image=sloogo.png |type=Sacred item |authors=The gods from beyond |maintainers=Gar |status=Eternal |releases=[https://github.com/DryCryCrystal/Region-Kit/releases GitHub (obviously)] }} <pre> {{Toolinfo |name=thing |noicon=yes |image=sloogo.png |type=Sacred item |authors=The gods from beyond |maintainers=Gar |status=Eternal |releases=[https://github.com/DryCryCrystal/Region-Kit/releases GitHub (obviously)] }} </pre> {|class="wikitable" |+ Fields ! Field !! Meaning |- | name || Infobox title |- | icon || icon image to be used |- | image || image to be used |- | type || Tool type (external program, script, macro etc) |- | authors || Parties involved in creation of the tool or its parts |- | maintainers || Parties persistently maintaining the tool |- | status || Support status of tool (Active development, LTS, Abandoned etc) |} </noinclude> <!-- stolen code from big sister to be removed ~~th --> 33c127f3238e1e17da5c6e403896bec59b8088ec 295 291 2022-08-20T13:46:08Z Thalber 3 wikitext text/x-wiki <includeonly>{|class="infoboxtable" |- <!-- header --> ! colspan="2" class="infoboxname" | "{{{name|{{PAGENAME}}}}}"<br>{{#if: {{{icon|}}} | [[File:{{{icon}}}]] | }} |- {{#if: {{{image|}}} | ! colspan="2" {{!}} [[File:{{{image}}}{{!}}{{{size|250x250px}}}]] | ! colspan="2" {{!}} ''No image''<!--{{#ifeq: {{NAMESPACE}} | Template | | [[Category:Infoboxes lacking images]]}} -->}} |- ! colspan="2" class="infoboxdetails" | Details <!-- body --> |- {{#if: {{{type|}}} | {{!}} {{!}} <div>Tool type</div> {{!!}} {{{type}}} }} |- {{#if: {{{license|}}} | {{!}} <div>License</div> {{!!}} {{{license}}} }} |- {{#if: {{{authors|}}} | {{!}} <div>Authors</div> {{!!}} {{{authors}}} }} |- {{#if: {{{maintainers|}}} | {{!}} <div>Maintainers</div> {{!!}} {{{maintainers}}} }} |- {{#if: {{{status|}}} | {{!}} <div>Status</div> {{!!}} {{{status}}} }} |- {{#if: {{{releases|}}} | {{!}} <div>Release links</div> {{!!}} {{{releases}}} }} |- |}</includeonly> <noinclude> == Usage == {{Toolinfo |name=thing |icon=hunterAngy.png |image=sloogo.png |type=Sacred item |authors=The gods from beyond |maintainers=Gar |status=Eternal |releases=[https://github.com/DryCryCrystal/Region-Kit/releases GitHub (obviously)] }} <pre> {{Toolinfo |name=thing |noicon=yes |image=sloogo.png |type=Sacred item |authors=The gods from beyond |maintainers=Gar |status=Eternal |releases=[https://github.com/DryCryCrystal/Region-Kit/releases GitHub (obviously)] }} </pre> {|class="wikitable" |+ Fields ! Field !! Meaning |- | name || Infobox title |- | icon || icon image to be used |- | image || image to be used |- | type || Tool type (external program, script, macro etc) |- | authors || Parties involved in creation of the tool or its parts |- | maintainers || Parties persistently maintaining the tool |- | status || Support status of tool (Active development, LTS, Abandoned etc) |} </noinclude> <!-- stolen code from big sister to be removed ~~th --> 65357149da9af1d3d27b1fa610d7ad07be962802 297 295 2022-08-20T13:49:55Z Thalber 3 wikitext text/x-wiki <includeonly>{|class="infoboxtable" |- <!-- header --> ! colspan="2" class="infoboxname" | "{{{name|{{PAGENAME}}}}}"<br>{{#if: {{{icon|}}} | [[File:{{{icon}}}]] | }} |- {{#if: {{{image|}}} | ! colspan="2" {{!}} [[File:{{{image}}}{{!}}{{{size|250x250px}}}]] | ! colspan="2" {{!}} ''No image''<!--{{#ifeq: {{NAMESPACE}} | Template | | [[Category:Infoboxes lacking images]]}} -->}} |- ! colspan="2" class="infoboxdetails" | Details <!-- body --> |- {{#if: {{{type|}}} | {{!}} {{!}} <div>Tool type</div> {{!!}} {{{type}}} }} |- {{#if: {{{license|}}} | {{!}} <div>License</div> {{!!}} {{{license}}} }} |- {{#if: {{{authors|}}} | {{!}} <div>Authors</div> {{!!}} {{{authors}}} }} |- {{#if: {{{maintainers|}}} | {{!}} <div>Maintainers</div> {{!!}} {{{maintainers}}} }} |- {{#if: {{{status|}}} | {{!}} <div>Status</div> {{!!}} {{{status}}} }} |- {{#if: {{{releases|}}} | {{!}} <div>Release links</div> {{!!}} {{{releases}}} }} |- |}</includeonly><noinclude> == Usage == {{Toolinfo |name=thing |icon=hunterAngy.png |image=sloogo.png |type=Sacred item |authors=The gods from beyond |maintainers=Gar |status=Eternal |releases=[https://github.com/DryCryCrystal/Region-Kit/releases GitHub (obviously)] }} <pre> {{Toolinfo |name=thing |noicon=yes |image=sloogo.png |type=Sacred item |authors=The gods from beyond |maintainers=Gar |status=Eternal |releases=[https://github.com/DryCryCrystal/Region-Kit/releases GitHub (obviously)] }} </pre> {|class="wikitable" |+ Fields ! Field !! Meaning |- | name || Infobox title |- | icon || icon image to be used |- | image || image to be used |- | type || Tool type (external program, script, macro etc) |- | authors || Parties involved in creation of the tool or its parts |- | maintainers || Parties persistently maintaining the tool |- | status || Support status of tool (Active development, LTS, Abandoned etc) |} </noinclude> <!-- stolen code from big sister to be removed ~~th --> d9d181d8dcd20eed2a5ca48be8013469aeadbffe Custom Regions Support 0 101 264 238 2022-08-18T11:26:13Z Thalber 3 Add infobox wikitext text/x-wiki {{Cleanup}} {{Toolinfo |name=Custom Regions Support |type=Core dependency mod |authors=Garrakx, Slime_Cubed, Henpemaz |maintainers=Garrakx |status=Supported |releases=[https://github.com/Garrakx/Custom-Regions GitHub] }} '''Custom Regions Support''' or '''CRS''' is a library/util mod that was created as an easier way to install [[Content Mods]], replacing file merging. It allows to install multiple region mods at once easily, quickly toggle them, and makes region development less messy. As of now, it is the primary way of installing any and all custom regions, and many of them are ''CRS-exclusive''. == Features == === Runtime worldfile merging === ''For basics of region architecture, see [[World File Format]]'' CRS attempts to smartly combine region world files and avoid room connectivity conflicts. It is the most effective if region mods don't distribute full modified copies of WORLD_XX.txt files for conflict-prone connection (such as vanilla region's WORLD_XX, when a modded region connects to it), and instead ''only include lines that need to be changed or added''. This is commonly referred to as "refining worldfiles". In addition to connection files, it can also merge region property files. === In-game downloader === CRS config menu allows the user to install most region packs from inside the game in one click, including their dependency DLLs, and also quickly toggle installed packs on and off. Downloader menu is reshuffled every day to give every CRS-published region a shot. === Region-conditional connections === Connections may be toggled depending on if a certain region is present: <pre> ROOMS (TM, !BL)roomA : roomB, roomD //only used if TM is installed and BL is not ENDROOMS </pre> This can be combined with unused vanilla behaviour of character-specific connections. === Connection fixer === Starting with v0.9.xx, CRS can attempt to fix some broken connections. This behaviour isn't a catchall but can make some conflicts less lethal. === Additional asset loading === CRS allows easily loading assets commonly bundled with most regions, such as music files, region splash art for passage/regions map screens, decals etc. === Misc === * Making previously hardcoded settings (electric gates, albino colouring on creatures, chance of salamander colouring etc) configurable with json files * Removing creature spawns * No-code addition of custom pearls * Adding unlockable arenas 52f7d45007cfd62debbdc11c537a11ee2c0b5f89 293 264 2022-08-20T13:40:20Z Thalber 3 wikitext text/x-wiki {{Toolinfo |name=Custom Regions Support |type=Core dependency mod |authors=Garrakx, Slime_Cubed, Henpemaz |maintainers=Garrakx |status=Supported |releases=[https://github.com/Garrakx/Custom-Regions GitHub] }} {{Cleanup}} '''Custom Regions Support''' or '''CRS''' is a library/util mod that was created as an easier way to install [[Content Mods]], replacing file merging. It allows to install multiple region mods at once easily, quickly toggle them, and makes region development less messy. As of now, it is the primary way of installing any and all custom regions, and many of them are ''CRS-exclusive''. == Features == === Runtime worldfile merging === ''For basics of region architecture, see [[World File Format]]'' CRS attempts to smartly combine region world files and avoid room connectivity conflicts. It is the most effective if region mods don't distribute full modified copies of WORLD_XX.txt files for conflict-prone connection (such as vanilla region's WORLD_XX, when a modded region connects to it), and instead ''only include lines that need to be changed or added''. This is commonly referred to as "refining worldfiles". In addition to connection files, it can also merge region property files. === In-game downloader === CRS config menu allows the user to install most region packs from inside the game in one click, including their dependency DLLs, and also quickly toggle installed packs on and off. Downloader menu is reshuffled every day to give every CRS-published region a shot. === Region-conditional connections === Connections may be toggled depending on if a certain region is present: <pre> ROOMS (TM, !BL)roomA : roomB, roomD //only used if TM is installed and BL is not ENDROOMS </pre> This can be combined with unused vanilla behaviour of character-specific connections. === Connection fixer === Starting with v0.9.xx, CRS can attempt to fix some broken connections. This behaviour isn't a catchall but can make some conflicts less lethal. === Additional asset loading === CRS allows easily loading assets commonly bundled with most regions, such as music files, region splash art for passage/regions map screens, decals etc. === Misc === * Making previously hardcoded settings (electric gates, albino colouring on creatures, chance of salamander colouring etc) configurable with json files * Removing creature spawns * No-code addition of custom pearls * Adding unlockable arenas 41eef93042432c509bb6841bb469ee67171bf6d2 296 293 2022-08-20T13:46:20Z Thalber 3 wikitext text/x-wiki {{Toolinfo |name=Custom Regions Support |type=Core dependency mod |authors=Garrakx, Slime_Cubed, Henpemaz |maintainers=Garrakx |status=Supported |releases=[https://github.com/Garrakx/Custom-Regions GitHub] }} {{Cleanup}} '''Custom Regions Support''' or '''CRS''' is a library/util mod that was created as an easier way to install [[Content Mods]], replacing file merging. It allows to install multiple region mods at once easily, quickly toggle them, and makes region development less messy. As of now, it is the primary way of installing any and all custom regions, and many of them are ''CRS-exclusive''. == Features == === Runtime worldfile merging === ''For basics of region architecture, see [[World File Format]]'' CRS attempts to smartly combine region world files and avoid room connectivity conflicts. It is the most effective if region mods don't distribute full modified copies of WORLD_XX.txt files for conflict-prone connection (such as vanilla region's WORLD_XX, when a modded region connects to it), and instead ''only include lines that need to be changed or added''. This is commonly referred to as "refining worldfiles". In addition to connection files, it can also merge region property files. === In-game downloader === CRS config menu allows the user to install most region packs from inside the game in one click, including their dependency DLLs, and also quickly toggle installed packs on and off. Downloader menu is reshuffled every day to give every CRS-published region a shot. === Region-conditional connections === Connections may be toggled depending on if a certain region is present: <pre> ROOMS (TM, !BL)roomA : roomB, roomD //only used if TM is installed and BL is not ENDROOMS </pre> This can be combined with unused vanilla behaviour of character-specific connections. === Connection fixer === Starting with v0.9.xx, CRS can attempt to fix some broken connections. This behaviour isn't a catchall but can make some conflicts less lethal. === Additional asset loading === CRS allows easily loading assets commonly bundled with most regions, such as music files, region splash art for passage/regions map screens, decals etc. === Misc === * Making previously hardcoded settings (electric gates, albino colouring on creatures, chance of salamander colouring etc) configurable with json files * Removing creature spawns * No-code addition of custom pearls * Adding unlockable arenas 8ea091d3dabd434f24198d4573207b1046b019ee 298 296 2022-08-20T13:51:03Z Thalber 3 wikitext text/x-wiki {{Toolinfo |name=Custom Regions Support |type=Core dependency mod |authors=Garrakx, Slime_Cubed, Henpemaz |maintainers=Garrakx |status=Supported |releases=[https://github.com/Garrakx/Custom-Regions GitHub] }} {{Cleanup}} '''Custom Regions Support''' or '''CRS''' is a library/util mod that was created as an easier way to install [[Content Mods]], replacing file merging. It allows to install multiple region mods at once easily, quickly toggle them, and makes region development less messy. As of now, it is the primary way of installing any and all custom regions, and many of them are ''CRS-exclusive''. == Features == === Runtime worldfile merging === ''For basics of region architecture, see [[World File Format]]'' CRS attempts to smartly combine region world files and avoid room connectivity conflicts. It is the most effective if region mods don't distribute full modified copies of WORLD_XX.txt files for conflict-prone connection (such as vanilla region's WORLD_XX, when a modded region connects to it), and instead ''only include lines that need to be changed or added''. This is commonly referred to as "refining worldfiles". In addition to connection files, it can also merge region property files. === In-game downloader === CRS config menu allows the user to install most region packs from inside the game in one click, including their dependency DLLs, and also quickly toggle installed packs on and off. Downloader menu is reshuffled every day to give every CRS-published region a shot. === Region-conditional connections === Connections may be toggled depending on if a certain region is present: <pre> ROOMS (TM, !BL)roomA : roomB, roomD //only used if TM is installed and BL is not ENDROOMS </pre> This can be combined with unused vanilla behaviour of character-specific connections. === Connection fixer === Starting with v0.9.xx, CRS can attempt to fix some broken connections. This behaviour isn't a catchall but can make some conflicts less lethal. === Additional asset loading === CRS allows easily loading assets commonly bundled with most regions, such as music files, region splash art for passage/regions map screens, decals etc. === Misc === * Making previously hardcoded settings (electric gates, albino colouring on creatures, chance of salamander colouring etc) configurable with json files * Removing creature spawns * No-code addition of custom pearls * Adding unlockable arenas 487f42cd4cc80c705022968268b627179f86fd18 BOI 0 110 267 247 2022-08-18T11:31:10Z Thalber 3 Add tool infobox wikitext text/x-wiki {{Toolinfo |type=Mod manager |authors=thalber |maintainers=thalber |status=LTS |releases=[https://github.com/Rain-World-Modding/BOI GitHub] }} '''BOI''' ''(an abbreviation of a horrendous pun)'' is an external mod manager for [[BepInEx]] initially created with the intent of making migration from [[Partiality]] easier. Glued together in Windows Forms and erratically maintained by a terminally clueless specimen since late 2020, it is a tall tower of bodges that somehow still stands. A hatchling-friendly tutorial to using it can be found [https://youtu.be/brDN_8uN6-U on YouTube]. Source code and releases can be found [https://github.com/Rain-World-Modding/BOI on GitHub]. == Features == === GUI wrapper === BOI has a somewhat straightforward UI for loading/enabling/disabling mods of most common kinds. It imitates the folder behaviour of [[Partiality]] (everything is stored in <code>Rain World/Mods/</code> before being moved to BepInEx active dirs) and attempts to automate some actions counterintuitive to the end user (like renaming assembly files for [[MonoModPatches]]). === Auto-installer === BOI can quickly install a latest valid [[BepInEx]] package and some of the more commonly used mods from [[AUDB]]. === Misc === * Detecting potentially faulty mods * Save state backups * Mod tags and bulk toggling * Post-PL folder cleanup * GUI wrappers for some mod configs == Installation == # Download latest release and unpack the archive. #* It is recommended to keep BOI in a separate folder. #* Make sure that all of archive contents are next to BOI.exe # Run BOI.exe. Press <code>Select path to game</code> ## Navigate to the game's .exe file ## Open it ## Press the same button again == Usage == {{todo}} [[Category:RW-Specific Tools]] 49b53775e5b9a8076c3a3863abe22d2273fca7f4 268 267 2022-08-18T11:34:50Z Thalber 3 wikitext text/x-wiki {{Toolinfo |type=Mod manager |authors=thalber |maintainers=thalber |status=LTS |releases=[https://github.com/Rain-World-Modding/BOI GitHub] }} '''BOI''' ''(an abbreviation of a horrendous pun)'' is an external mod manager for [[BepInEx]] initially created with the intent of making migration from [[Partiality]] easier. Glued together in Windows Forms and erratically maintained by a terminally clueless specimen since late 2020, it is a tall tower of bodges that somehow still stands. A hatchling-friendly tutorial to using it can be found [https://youtu.be/brDN_8uN6-U on YouTube]. == Features == === GUI wrapper === BOI has a somewhat straightforward UI for loading/enabling/disabling mods of most common kinds. It imitates the folder behaviour of [[Partiality]] (everything is stored in <code>Rain World/Mods/</code> before being moved to BepInEx active dirs) and attempts to automate some actions counterintuitive to the end user (like renaming assembly files for [[MonoModPatches]]). === Auto-installer === BOI can quickly install a latest valid [[BepInEx]] package and some of the more commonly used mods from [[AUDB]]. === Misc === * Detecting potentially faulty mods * Save state backups * Mod tags and bulk toggling * Post-PL folder cleanup * GUI wrappers for some mod configs == Installation == # Download latest release and unpack the archive. #* It is recommended to keep BOI in a separate folder. #* Make sure that all of archive contents are next to BOI.exe # Run BOI.exe. Press <code>Select path to game</code> ## Navigate to the game's .exe file ## Open it ## Press the same button again == Usage == {{todo}} [[Category:RW-Specific Tools]] c2bc6af83f749fc147a17f9a3e578e4f21964f6b 269 268 2022-08-18T11:36:45Z Thalber 3 wikitext text/x-wiki {{Toolinfo |type=Mod manager |authors=thalber |maintainers=thalber |status=LTS |license=The Unlicense |releases=[https://github.com/Rain-World-Modding/BOI GitHub] }} '''BOI''' ''(an abbreviation of a horrendous pun)'' is an external mod manager for [[BepInEx]] initially created with the intent of making migration from [[Partiality]] easier. Glued together in Windows Forms and erratically maintained by a terminally clueless specimen since late 2020, it is a tall tower of bodges that somehow still stands. A hatchling-friendly tutorial to using it can be found [https://youtu.be/brDN_8uN6-U on YouTube]. == Features == === GUI wrapper === BOI has a somewhat straightforward UI for loading/enabling/disabling mods of most common kinds. It imitates the folder behaviour of [[Partiality]] (everything is stored in <code>Rain World/Mods/</code> before being moved to BepInEx active dirs) and attempts to automate some actions counterintuitive to the end user (like renaming assembly files for [[MonoModPatches]]). === Auto-installer === BOI can quickly install a latest valid [[BepInEx]] package and some of the more commonly used mods from [[AUDB]]. === Misc === * Detecting potentially faulty mods * Save state backups * Mod tags and bulk toggling * Post-PL folder cleanup * GUI wrappers for some mod configs == Installation == # Download latest release and unpack the archive. #* It is recommended to keep BOI in a separate folder. #* Make sure that all of archive contents are next to BOI.exe # Run BOI.exe. Press <code>Select path to game</code> ## Navigate to the game's .exe file ## Open it ## Press the same button again == Usage == {{todo}} [[Category:RW-Specific Tools]] 01ad47a7b6cf4e34d5c367fdd6c60ed58aaf0a21 299 269 2022-08-20T13:56:24Z Thalber 3 wikitext text/x-wiki {{Toolinfo |type=Mod manager |authors=thalber |maintainers=thalber |status=LTS |license=The Unlicense |releases=[https://github.com/Rain-World-Modding/BOI GitHub] }} '''BOI''' ''(an abbreviation of a horrendous pun)'' is an external mod manager for [[BepInEx]] initially created with the intent of making migration from [[Partiality]] easier. Glued together in Windows Forms and erratically maintained by a terminally clueless specimen since late 2020, it is a tall tower of bodges that somehow still stands. A hatchling-friendly tutorial to using it can be found [https://youtu.be/brDN_8uN6-U on YouTube]. == Features == === GUI wrapper === BOI has a somewhat straightforward UI for loading/enabling/disabling mods of most common kinds. It imitates the folder behaviour of [[Partiality]] (everything is stored in <code>Rain World/Mods/</code> before being moved to BepInEx active dirs) and attempts to automate some actions counterintuitive to the end user (like renaming assembly files for [[MonoModPatches]]). === Auto-installer === BOI can quickly install a latest valid [[BepInEx]] package and some of the more commonly used mods from [[AUDB]]. === Misc === * Detecting potentially faulty mods * Save state backups * Mod tags and bulk toggling * Post-PL folder cleanup * GUI wrappers for some mod configs == Installation == # Download latest release and unpack the archive. #* It is recommended to keep BOI in a separate folder. #* Make sure that all of archive contents are next to BOI.exe # Run BOI.exe. Press <code>Select path to game</code> ## Navigate to the game's .exe file ## Open it ## Press the same button again == Usage == {{todo}} [[Category:RW-Specific Tools]] 7ddbfa59ff1b370b0f530e52ec38e55513f8c5ee EnumExtender 0 94 270 183 2022-08-18T11:51:36Z Thalber 3 Add infobox, restructure wikitext text/x-wiki <!--{{Cleanup}}--> {{Toolinfo |type=Dependency library |authors=Bee |license=CC0 |releases=[https://github.com/aaay-aaay/EnumExtender source], [https://beestuff.pythonanywhere.com/audb/api/mods/0/1/download/latest latest build] }} '''EnumExtender''' or '''EE''' is a tool mod which allows adding entries to <code>Enum</code>s. It is widely used as a dependency library. == Features == EE allows the user to add entries to enums at runtime in two ways: * Automatic (does not require referencing EE assembly in your project) * Manual (requires referencing EE assembly in your project) == Usage == === Automatic extension === On initialization, EE scans all loaded classes, looking for <code>public static class</code> with names starting with <code>EnumExt_</code>. Extensions are created from <code>public static</code> fields with the type of target enum. Created entries have the same name as the field, and the field gets the value of the new entry. Example use: <syntaxhighlight lang="csharp"> public static class EnumExt_MyMod { // You can have multiple EnumExt_ classes in your assembly if you need multiple items with the same name for the different enum //this adds entry "Vultures" to enum "CreatureCommnuities.CommunityID" public static CreatureCommnuities.CommunityID Vultures; //this adds "YellowishWhite" to "SlugcatStats.Name" public static SlugcatStats.Name YellowishWhite; public static SlugcatStats.Name WhitishYellow; } </syntaxhighlight> To access these new enum items, instead of <code>[enum].[item]</code>, use that static field. To compare it, use <code>if</code> statements (unfortunately, you can not use static fields for branches in a <code>switch</code> statement). Example use: <syntaxhighlight lang="csharp"> public static SlugStatsPatch(On.SlugcatStats.orig_ctor orig, SlugcatStats stats, int slugcatNumber, bool malnourished) {     orig.Invoke(stats, slugcatNumber, malnourished);     if (stats.name == EnumExt_MyMod.YellowishWhite)     {         stats.runspeedFac = 1.2f;         stats.poleClimbSpeedFac = 1.25f;         stats.corridorClimbSpeedFac = 1.2f;     } } </syntaxhighlight> However, if EnumExtender is not present in runtime (for instance, the user forgot to install EnumExtender), these fields won't be initialized and will always stay at 0. This can be used to easily detect whether EnumExtender is installed or not. <syntaxhighlight lang="csharp"> public static bool HasEnumExt => (int)EnumExt_MyMod.YellowishWhite > 0; // This property returns true after EE initializes (after OnEnable) </syntaxhighlight> ==== Switch statement workaround ==== If you have multiple new items and really want to use switches, you can do something like the following: <syntaxhighlight lang="csharp"> public static class EnumSwitch { //the intermediary enum     public enum SlugcatStatsName     {         DEFAULT = -1, // unrelated to this mod         YellowishWhite,         WhitishYellow     };     public static SlugcatStatsName GetSlugStatsNameInterm(SlugcatStats.Name name)     {         if (!HasEnumExt) { return SlugcatStatsName.DEFAULT; } // EnumExt is not installed         if (name == EnumExt_MyMod.YellowishWhite) { return SlugcatStatsName.YellowishWhite; }         if (name == EnumExt_MyMod.WhitishYellow) { return SlugcatStatsName.WhitishYellow; }         return SlugcatStatsName.DEFAULT;     } } </syntaxhighlight> And when you need to use switch later, <syntaxhighlight lang="csharp"> switch (EnumSwitch.GetSlugStatsNameInterm(name)) {     default:     case SlugcatStatsName.DEFAULT: break;     case SlugcatStatsName.YellowishWhite:         break;     case SlugcatStatsName.WhitishYellow:         break; } </syntaxhighlight> <!--ehhhh this was a bad idea '''Alternatively''', if you want to use one switch statement containing checks for both vanilla and intermediary enum, you can # give an explicit value to the interm enum, ideally some really large numbers so that it doesn't collide with any vanilla values # modify interm method (<code>GetSlugStatsNameInterm</code> in the example) to return an int and return original value as int when EE is not installed # instead of switching over <syntaxhighlight lang="charp"> //... //... </syntaxhighlight> --> === Manual extension === This method is useful when you don't know what name your new entries will have to have. It is more cumbersome to use and less safe, but # Ensure that EE has been initialized. You can either wait until the <code>EnumExt_</code> get appropriate values, or call <code>PastebinMachine.EnumExtender.EnsureInit()</code> # Call <code>PastebinMachine.EnumExtender.AddDeclaration(Type, string)</code> one or more times. First parameter is <code>Type</code> of the enum, second is the name of new entry. '''Ensuring there are no name collisions is on you!''' # Call <code>PastebinMachine.EnumExtender.ExtendEnumsAgain</code> ''once'' to register all your new enums. '''NOTE''': Last step may have a noticeable overhead, and each call to <code>ExtendEnumsAgain</code> causes a small but permanent memory leak. Do not overuse. <code>ExtendEnumsAgain</code> does not return the added values, you have to obtain them manually through <code>Enum.GetNames()</code> or <code>Enum.GetValues()</code>. Storing the resulting values correctly is the user's responsibility. == Summary == Both modes allow you to use methods like <code>Enum.Parse</code> with extended values freely. RW codebase uses enums pretty much everywhere, so EnumExtender is a often a vital dependency. [[Category:Code Mods]] [[Category:Dependencies]] c4e783834b4805276530cd5e282c0e1baa963856 300 270 2022-08-20T13:57:20Z Thalber 3 wikitext text/x-wiki {{Toolinfo |type=Dependency library |authors=Bee |license=CC0 |releases=[https://github.com/aaay-aaay/EnumExtender source], [https://beestuff.pythonanywhere.com/audb/api/mods/0/1/download/latest latest build] }} '''{{PAGENAME}}''' or '''EE''' is a tool mod which allows adding entries to <code>Enum</code>s. It is widely used as a dependency library. == Features == EE allows the user to add entries to enums at runtime in two ways: * Automatic (does not require referencing EE assembly in your project) * Manual (requires referencing EE assembly in your project) == Usage == === Automatic extension === On initialization, EE scans all loaded classes, looking for <code>public static class</code> with names starting with <code>EnumExt_</code>. Extensions are created from <code>public static</code> fields with the type of target enum. Created entries have the same name as the field, and the field gets the value of the new entry. Example use: <syntaxhighlight lang="csharp"> public static class EnumExt_MyMod { // You can have multiple EnumExt_ classes in your assembly if you need multiple items with the same name for the different enum //this adds entry "Vultures" to enum "CreatureCommnuities.CommunityID" public static CreatureCommnuities.CommunityID Vultures; //this adds "YellowishWhite" to "SlugcatStats.Name" public static SlugcatStats.Name YellowishWhite; public static SlugcatStats.Name WhitishYellow; } </syntaxhighlight> To access these new enum items, instead of <code>[enum].[item]</code>, use that static field. To compare it, use <code>if</code> statements (unfortunately, you can not use static fields for branches in a <code>switch</code> statement). Example use: <syntaxhighlight lang="csharp"> public static SlugStatsPatch(On.SlugcatStats.orig_ctor orig, SlugcatStats stats, int slugcatNumber, bool malnourished) {     orig.Invoke(stats, slugcatNumber, malnourished);     if (stats.name == EnumExt_MyMod.YellowishWhite)     {         stats.runspeedFac = 1.2f;         stats.poleClimbSpeedFac = 1.25f;         stats.corridorClimbSpeedFac = 1.2f;     } } </syntaxhighlight> However, if EnumExtender is not present in runtime (for instance, the user forgot to install EnumExtender), these fields won't be initialized and will always stay at 0. This can be used to easily detect whether EnumExtender is installed or not. <syntaxhighlight lang="csharp"> public static bool HasEnumExt => (int)EnumExt_MyMod.YellowishWhite > 0; // This property returns true after EE initializes (after OnEnable) </syntaxhighlight> ==== Switch statement workaround ==== If you have multiple new items and really want to use switches, you can do something like the following: <syntaxhighlight lang="csharp"> public static class EnumSwitch { //the intermediary enum     public enum SlugcatStatsName     {         DEFAULT = -1, // unrelated to this mod         YellowishWhite,         WhitishYellow     };     public static SlugcatStatsName GetSlugStatsNameInterm(SlugcatStats.Name name)     {         if (!HasEnumExt) { return SlugcatStatsName.DEFAULT; } // EnumExt is not installed         if (name == EnumExt_MyMod.YellowishWhite) { return SlugcatStatsName.YellowishWhite; }         if (name == EnumExt_MyMod.WhitishYellow) { return SlugcatStatsName.WhitishYellow; }         return SlugcatStatsName.DEFAULT;     } } </syntaxhighlight> And when you need to use switch later, <syntaxhighlight lang="csharp"> switch (EnumSwitch.GetSlugStatsNameInterm(name)) {     default:     case SlugcatStatsName.DEFAULT: break;     case SlugcatStatsName.YellowishWhite:         break;     case SlugcatStatsName.WhitishYellow:         break; } </syntaxhighlight> <!--ehhhh this was a bad idea '''Alternatively''', if you want to use one switch statement containing checks for both vanilla and intermediary enum, you can # give an explicit value to the interm enum, ideally some really large numbers so that it doesn't collide with any vanilla values # modify interm method (<code>GetSlugStatsNameInterm</code> in the example) to return an int and return original value as int when EE is not installed # instead of switching over <syntaxhighlight lang="charp"> //... //... </syntaxhighlight> --> === Manual extension === This method is useful when you don't know what name your new entries will have to have. It is more cumbersome to use and less safe, but # Ensure that EE has been initialized. You can either wait until the <code>EnumExt_</code> get appropriate values, or call <code>PastebinMachine.EnumExtender.EnsureInit()</code> # Call <code>PastebinMachine.EnumExtender.AddDeclaration(Type, string)</code> one or more times. First parameter is <code>Type</code> of the enum, second is the name of new entry. '''Ensuring there are no name collisions is on you!''' # Call <code>PastebinMachine.EnumExtender.ExtendEnumsAgain</code> ''once'' to register all your new enums. '''NOTE''': Last step may have a noticeable overhead, and each call to <code>ExtendEnumsAgain</code> causes a small but permanent memory leak. Do not overuse. <code>ExtendEnumsAgain</code> does not return the added values, you have to obtain them manually through <code>Enum.GetNames()</code> or <code>Enum.GetValues()</code>. Storing the resulting values correctly is the user's responsibility. == Summary == Both modes allow you to use methods like <code>Enum.Parse</code> with extended values freely. RW codebase uses enums pretty much everywhere, so EnumExtender is a often a vital dependency. [[Category:Code Mods]] [[Category:Dependencies]] dbe1594741dfeb2f7098705052c4abd360c582b9 Downpour Reference 0 144 273 2022-08-20T07:47:21Z Thalber 3 Created page with "This section is ported from [https://andrew.fm/downpour_dev/index.html AndrewFM's spec page]. It contains description of both Remix usage and notable changes to incoming vanilla architecture. '''Remix''' is a modloader to be included with the game starting with release of Downpour. It is based on [[BepInEx]], and features an in-game mod management menu much like [[Realm]]. == Technical reference == * [[/Mod_Directories]] - Mod folder structure * [[/File_Formats]] - Ch..." wikitext text/x-wiki This section is ported from [https://andrew.fm/downpour_dev/index.html AndrewFM's spec page]. It contains description of both Remix usage and notable changes to incoming vanilla architecture. '''Remix''' is a modloader to be included with the game starting with release of Downpour. It is based on [[BepInEx]], and features an in-game mod management menu much like [[Realm]]. == Technical reference == * [[/Mod_Directories]] - Mod folder structure * [[/File_Formats]] - Changes in game file formats * [[/Modification_Files]] - Asset-driven file merging * [[/BepInEx_Files]] - handling of mods' .dll files * [[/ExtEnum]] - built-in replacement for [[EnumExtender]] * [[/Conflict_Merging]] - automatic conflict resolution 6376a79cbc5b77f4b23a7d357bc41af47c7b9a6a 280 273 2022-08-20T08:07:19Z Thalber 3 Protected "[[Downpour Reference]]": Official specs page ([Edit=Allow only administrators] (indefinite)) [cascading] wikitext text/x-wiki This section is ported from [https://andrew.fm/downpour_dev/index.html AndrewFM's spec page]. It contains description of both Remix usage and notable changes to incoming vanilla architecture. '''Remix''' is a modloader to be included with the game starting with release of Downpour. It is based on [[BepInEx]], and features an in-game mod management menu much like [[Realm]]. == Technical reference == * [[/Mod_Directories]] - Mod folder structure * [[/File_Formats]] - Changes in game file formats * [[/Modification_Files]] - Asset-driven file merging * [[/BepInEx_Files]] - handling of mods' .dll files * [[/ExtEnum]] - built-in replacement for [[EnumExtender]] * [[/Conflict_Merging]] - automatic conflict resolution 6376a79cbc5b77f4b23a7d357bc41af47c7b9a6a Downpour Reference/Mod Directories 0 145 274 2022-08-20T07:53:35Z Thalber 3 Port DPref/ModDirs wikitext text/x-wiki {{Cleanup}} Each mod in Downpour is stored as a subfolder inside the &quot;Assets/StreamingAssets/mods&quot; directory. This subfolder contains all metadata, file modifications and overrides, assets, and code modules (DLL files) that define the mod's contents and functionality. == ModInfo JSON == Each mod should have a &quot;modinfo.json&quot; file included in the top level directory of the mod. This JSON file defines the metadata for the mod, mainly the information that will be displayed for that mod within the REMIX menu. The following key-value pairs exist for this JSON file: * '''id''': This is a unique string identifier for this mod. This identifier should never be changed. Recommended to be a lower-case string with no spaces. Other mods will reference this ID to refer to your mod, such as when listing mod requirements. * '''name''': This is the title of your mod that will be shown and listed in the REMIX menu. * '''version''': This is a string specifying the current version number of your mod. * '''authors''': A string listing the authors of the mod. The &lt;LINE&gt; keyword can be used to add a breakline. If the authors string is too long to be displayed directly, it will be converted to a credits roll in the REMIX menu. * '''description''': A longer description of the functionality of the mod, to be displayed in the REMIX menu. The &lt;LINE&gt; keyword can be used to add a breakline. * '''requirements''': An array of strings specifying other mods which must be installed to use this mod. Each string in the array should match the '''id''' key of the required mod. * '''requirements_names''': A parallel array to the '''requirements''' array, which you can use to display more user friendly names for the requirements in the REMIX menu rather than displaying their internal '''id''' string. * '''checksum_override_version''': An optional boolean parameter. If false, or omitted, the mod will be considered &quot;updated&quot; if changes are found to any files in the mod's folder. If true, the mod will only be considered &quot;updated&quot; if the value of the '''version''' parameter changes. An example modinfo.json file contents: <pre>{ &quot;id&quot;: &quot;testmod&quot;, &quot;name&quot;: &quot;Test Mod&quot;, &quot;version&quot;: &quot;1.0&quot;, &quot;authors&quot;: &quot;AndrewFM&quot;, &quot;description&quot;: &quot;This mod does something interesting, probably!&quot;, &quot;requirements&quot;: [&quot;bestmod&quot;, &quot;vrmod&quot;], &quot;requirements_names&quot;: [&quot;That Other Mod&quot;, &quot;Virtual Reality Support&quot;], &quot;checksum_override_version&quot;: false }</pre> In addition to the modinfo.json file, the mod directory can also include a '''thumbnail.png''' image to be displayed in the REMIX menu. The recommended resolution of this image is 360x250. == Overwriting Files == The contents of the mod folder are a mirror of the StreamingAssets folder. For example, if you wanted your mod to replace the image file at:<br /> <br />      &quot;''Assets/StreamingAssets/futile/resources/illustrations/maintitle.png''&quot;<br /> <br /> with a different image, you would place the new image at:<br /> <br />      &quot;''your-mod-folder/futile/resources/illustrations/maintitle.png''&quot;<br /> <br /> Since the directory structure and file name match one of the original game's files, the game will use the version from your mod directory instead of the original version of the file, whenever your mod is enabled. In some cases files outside the StreamingAssets folder can be modified as well. For example to modify sound effects (Assets/LoadedSoundEffects) your folder structure would be:<br /> <br />      &quot;''your-mod-folder/futile/resources/loadedsoundeffects/...''&quot;<br /> <br /> Or to modify music files (Assets/Music), the structure would be:<br /> <br />      &quot;''your-mod-folder/futile/resources/music/...''&quot;<br /> <br /> Refer to [[Downpour Reference/Modification Files]] for other ways to modify existing files other than completely overwriting their contents, for better mod compatibility. == AssetManager == Whenever referencing any asset files from disk in your code (whether they be files from within your mod's folder, or files within the base game's folders), you should use the static utility functions offered by the AssetManager class. This ensures the file path to the correct version of the file is used based on which mods are enabled or disabled, following the logic above. For example: <pre>AssetManager.ResolveFilePath(&quot;futile/resources/illustrations/maintitle.png&quot;);</pre> This would return the file path to the vanilla maintitle.png file. However, if the example mod described in the previous section were enabled, this instead would return the file path to that mod's overwritten version of maintitle.png. The available utility functions are: * '''ResolveFilePath(path)''': Return the correct path to the given file based on enabled/disabled mods. * '''ResolveDirectory(path)''': Return the correct path to the given subdirectory based on enabled/disabled mods. * '''ListDirectory(path)''': Returns all unique files contained in all versions of the given subdirectory based on enabled/disabled mods. * '''ListDirectory(path, true)''': Returns all unique subdirectories contained in all versions of the given subdirectory based on enabled/disabled mods. To give an example of ListDirectory, consider a hypothetical vanilla directory at:<br /> <br />      &quot;''Assets/StreamingAssets/futile/resources/example''&quot;<br /> <br /> which contained the files &quot;a.txt&quot;, &quot;b.txt&quot;, and &quot;c.txt&quot;. Then say you created a mod which included the folder:<br /> <br />      &quot;''your-mod-folder/futile/resources/example''&quot;<br /> <br /> which contained the files &quot;c.txt&quot;, and &quot;d.txt&quot;. Then when the code below is executed: <pre>AssetManager.ListDirectory(&quot;futile/resources/example&quot;);</pre> If your mod is disabled, the files &quot;a.txt&quot; (vanilla), &quot;b.txt&quot; (vanilla), &quot;c.txt&quot; (vanilla) would be returned. If your mod is enabled, the files &quot;a.txt&quot; (vanilla), &quot;b.txt&quot; (vanilla), &quot;c.txt&quot; (modded), &quot;d.txt&quot; (modded) would be returned. d17dee7096a0e36ba23c47f8193643a0bb1c0f25 281 274 2022-08-20T08:31:55Z Thalber 3 fix formatting wikitext text/x-wiki Each mod in Downpour is stored as a subfolder inside the &quot;Assets/StreamingAssets/mods&quot; directory. This subfolder contains all metadata, file modifications and overrides, assets, and code modules (DLL files) that define the mod's contents and functionality. == ModInfo JSON == Each mod should have a &quot;modinfo.json&quot; file included in the top level directory of the mod. This JSON file defines the metadata for the mod, mainly the information that will be displayed for that mod within the REMIX menu. The following key-value pairs exist for this JSON file: {|class="wikitable" ! Key !! Meaning |- | id || This is a unique string identifier for this mod. This identifier should never be changed. Recommended to be a lower-case string with no spaces. Other mods will reference this ID to refer to your mod, such as when listing mod requirements. |- | name || This is the title of your mod that will be shown and listed in the REMIX menu. |- | version || This is a string specifying the current version number of your mod. |- | authors || A string listing the authors of the mod. The &lt;LINE&gt; keyword can be used to add a breakline. If the authors string is too long to be displayed directly, it will be converted to a credits roll in the REMIX menu. |- | description || A longer description of the functionality of the mod, to be displayed in the REMIX menu. The &lt;LINE&gt; keyword can be used to add a breakline. |- | requirements || An array of strings specifying other mods which must be installed to use this mod. Each string in the array should match the '''id''' key of the required mod. |- | requirements_names || A parallel array to the '''requirements''' array, which you can use to display more user friendly names for the requirements in the REMIX menu rather than displaying their internal '''id''' string. |- | checksum_override_version || An optional boolean parameter. If false, or omitted, the mod will be considered &quot;updated&quot; if changes are found to any files in the mod's folder. If true, the mod will only be considered &quot;updated&quot; if the value of the '''version''' parameter changes. |} An example modinfo.json file contents: <syntaxhighlight lang="json"> { "id": "testmod", "name": "Test Mod", "version": "1.0", "authors": "AndrewFM", "description": "This mod does something interesting, probably!", "requirements": ["bestmod", "vrmod"], "requirements_names": ["That Other Mod", "Virtual Reality Support"], "checksum_override_version": false } </syntaxhighlight> In addition to the modinfo.json file, the mod directory can also include a '''thumbnail.png''' image to be displayed in the REMIX menu. The recommended resolution of this image is 360x250. == Overwriting Files == The contents of the mod folder are a mirror of the StreamingAssets folder. For example, if you wanted your mod to replace the image file at: <pre>      "Assets/StreamingAssets/futile/resources/illustrations/maintitle.png" </pre> with a different image, you would place the new image at: <pre>      "your-mod-folder/futile/resources/illustrations/maintitle.png" </pre> Since the directory structure and file name match one of the original game's files, the game will use the version from your mod directory instead of the original version of the file, whenever your mod is enabled. In some cases files outside the StreamingAssets folder can be modified as well. For example to modify sound effects (Assets/LoadedSoundEffects) your folder structure would be: <pre>      "your-mod-folder/futile/resources/loadedsoundeffects/..." </pre> Or to modify music files (Assets/Music), the structure would be: <pre>      "your-mod-folder/futile/resources/music/..." </pre> Refer to [[Downpour Reference/Modification Files]] for other ways to modify existing files other than completely overwriting their contents, for better mod compatibility. == AssetManager == Whenever referencing any asset files from disk in your code (whether they be files from within your mod's folder, or files within the base game's folders), you should use the static utility functions offered by the AssetManager class. This ensures the file path to the correct version of the file is used based on which mods are enabled or disabled, following the logic above. For example: <pre>AssetManager.ResolveFilePath(&quot;futile/resources/illustrations/maintitle.png&quot;);</pre> This would return the file path to the vanilla maintitle.png file. However, if the example mod described in the previous section were enabled, this instead would return the file path to that mod's overwritten version of maintitle.png. The available utility functions are: {|class="wikitable" ! Method !! Meaning |- | '''ResolveFilePath(path)''' || Return the correct path to the given file based on enabled/disabled mods. |- | '''ResolveDirectory(path)''' || Return the correct path to the given subdirectory based on enabled/disabled mods. |- | '''ListDirectory(path)''' || Returns all unique files contained in all versions of the given subdirectory based on enabled/disabled mods. |- | '''ListDirectory(path, true)''' || Returns all unique subdirectories contained in all versions of the given subdirectory based on enabled/disabled mods. |} To give an example of ListDirectory, consider a hypothetical vanilla directory at: <pre>      "Assets/StreamingAssets/futile/resources/example"<br /> </pre> which contained the files "a.txt", "b.txt", and "c.txt". Then say you created a mod which included the folder: <pre>      "your-mod-folder/futile/resources/example"<br /> </pre> which contained the files "c.txt", and "d.txt". Then when the code below is executed: <pre> AssetManager.ListDirectory("futile/resources/example"); </pre> If your mod is disabled, the files "a.txt" (vanilla), "b.txt" (vanilla), "c.txt" (vanilla) would be returned. If your mod is enabled, the files "a.txt" (vanilla), "b.txt" (vanilla), "c.txt" (modded), "d.txt" (modded) would be returned. e9c409d5f9d7904d3a8c86e4640cb5039bf02a1d Downpour Reference/Modification Files 0 146 275 2022-08-20T07:56:37Z Thalber 3 Port DPref/ModifFiles wikitext text/x-wiki {{Cleanup}} Modification files are a method to specify rules to partially modify the contents an existing (non-binary) file, rather than replacing that file's contents completely. For compatibility between mods, these are preferable, as multiple mods can apply modifications to the same file without overwriting each other's changes. Think of this like the file system equivalent of a hook mod versus a patch mod. == Modification Directory Structure == Targeting a file for modification works similarly to targeting a file for overwriting. The difference is that these modification files are placed within an additional subdirectory within your mod folder called &quot;'''modify'''&quot;. For example, for the file:<br /> <br />      &quot;''Assets/StreamingAssets/world/gates/locks.txt''&quot;<br /> <br /> Placing a file at:<br /> <br />      &quot;''your-mod-folder/world/gates/locks.txt''&quot;<br /> <br /> Would cause the entire contents of locks.txt to be overwritten by the entire contents of the locks.txt file in your mod's folder. However, placing a modification file at:<br /> <br />      &quot;''your-mod-folder/modify/world/gates/locks.txt''&quot;<br /> <br /> Would apply the modification syntax within that locks.txt file to partially modify the contents of the original locks.txt file. == Modification File Syntax == Each line of a modification file includes an operation followed by the text that the operation uses for applying its effect. The available operations are: * '''[ADD]''' Appends the specified text to the end of the file. * '''[ADD_XX]''' Inserts the specified text after the XXth line in the file. * '''[FIND]''' Set a specific string as a target for a subsequent replace operation. * '''[FINDREGEX]''' Set a specific regex pattern as the target for a subsequent replace operation. * '''[REPLACE]''' Replace all instances of the target from the preceding find operation with the given text. * '''[REPLACE_XX]''' Replace the XXth instance of the target from the preceding find operation with the given text. If a new-line character needs to be matched or added, use the \n escape character to represent the new line. Also note that you can effectively do a delete operation as well by using [FIND]/[REPLACE] operations to replace the target with an empty string. Below is an example modification file: <pre>[ADD]Hello World [ADD_5]Slugcat\nRain World [FIND]Spider [REPLACE]Centipede [FINDREGEX](Green,Blue,Pink) [REPLACE_1]Red</pre> The above example modification file performs the following actions: # Appends a new line to the end of the file containing the text &quot;Hello World&quot;. # Inserts two new lines after line 5 in the file, the first containing the text &quot;Slugcat&quot; and the second containing the text &quot;Rain World&quot;. # Finds all instances of the text &quot;Spider&quot; in the file and replaces all those instances with the text &quot;Centipede&quot;. # Finds any instances of the text &quot;Green&quot;, &quot;Blue&quot;, or &quot;Pink&quot; in the file, and replaces only the first instance it finds with the text &quot;Red&quot;. == Merge Operation == Modification files have one more operation that is used by placing any number of lines of text between a '''[MERGE]''' and an '''[ENDMERGE]''' tag. The contents within will be &quot;merged&quot; with the contents of the original file in a way that is context dependent on the file you are applying the merge to. This section describes how this merging works for different vanilla source files: '''mpmusic.txt, regions.txt, egates.txt''' Applying merging to one of the files above will take any lines within the merge context and append them to the file, only if that line does not already exist in the file. '''default aligments.txt, sounds.txt, locks.txt, properties.txt, map_XX.txt''' Applies merging similarly to above, but takes key-value context into account. If a key doesn't exist in the file, the key-value pair will be appended to the file. If a key does exist in the file, then its value will be replaced by the new value in the merge context. '''Room Settings files''' Applies merging similarly to above, but certain keys have special handling. Effects, PlacedObjects, AmbientSounds, and Triggers will be merged additively, so the resulting room settings file will have all of the objects from the original room settings file, plus all of the new objects specified within the merge context. '''world_XX files''' Applies merging of world file contents in a CRS-style fashion. '''short_strings file''' Applying merging to a short_strings file will unencrypt the short_strings file, append any key-value pairs within the merge context if the key doesn't already exist (otherwise update the value to the new value), and then finally encrypt the short_strings file again. '''anything else''' Any other files not described above, will have their entire contents simply replaced with the contents of the merge context. 7800dd56b9997396f976e8c6dc5e28a4f0a099b6 284 275 2022-08-20T11:35:05Z Thalber 3 fix formatting wikitext text/x-wiki Modification files are a method to specify rules to partially modify the contents an existing (non-binary) file, rather than replacing that file's contents completely. For compatibility between mods, these are preferable, as multiple mods can apply modifications to the same file without overwriting each other's changes. Think of this like the file system equivalent of a hook mod versus a patch mod. == Modification Directory Structure == Targeting a file for modification works similarly to targeting a file for overwriting. The difference is that these modification files are placed within an additional subdirectory within your mod folder called <code>modify</code>. For example, for the file: : <code>Assets/StreamingAssets/world/gates/locks.txt</code> Placing a file at: : <code>your-mod-folder/world/gates/locks.txt</code> Would cause the entire contents of locks.txt to be overwritten by the entire contents of the locks.txt file in your mod's folder. However, placing a modification file at: : <code>your-mod-folder/modify/world/gates/locks.txt</code> Would apply the modification syntax within that locks.txt file to partially modify the contents of the original locks.txt file. == Modification File Syntax == Each line of a modification file includes an operation followed by the text that the operation uses for applying its effect. {|class="wikitable" |+Available operations ! Keyword !! Action |- | '''[ADD]''' || Appends the specified text to the end of the file. |- | '''[ADD_XX]''' || Inserts the specified text after the XXth line in the file. |- | '''[FIND]''' || Set a specific string as a target for a subsequent replace operation. |- | '''[FINDREGEX]''' || Set a specific regex pattern as the target for a subsequent replace operation. |- | '''[REPLACE]''' || Replace all instances of the target from the preceding find operation with the given text. |- | '''[REPLACE_XX]''' || Replace the XXth instance of the target from the preceding find operation with the given text. |} If a new-line character needs to be matched or added, use the \n escape character to represent the new line. Also note that you can effectively do a delete operation as well by using [FIND]/[REPLACE] operations to replace the target with an empty string. Below is an example modification file: <pre>[ADD]Hello World [ADD_5]Slugcat\nRain World [FIND]Spider [REPLACE]Centipede [FINDREGEX](Green,Blue,Pink) [REPLACE_1]Red</pre> The above example modification file performs the following actions: # Appends a new line to the end of the file containing the text "Hello World". # Inserts two new lines after line 5 in the file, the first containing the text "Slugcat" and the second containing the text "Rain World". # Finds all instances of the text "Spider" in the file and replaces all those instances with the text "Centipede". # Finds any instances of the text "Green", "Blue", or "Pink" in the file, and replaces only the first instance it finds with the text "Red". == Merge Operation == Modification files have one more operation that is used by placing any number of lines of text between a <code>[MERGE]</code> and an <code>[ENDMERGE]</code> tag. The contents within will be "merged" with the contents of the original file in a way that is context dependent on the file you are applying the merge to. This section describes how this merging works for different vanilla source files: {|class="wikitable" ! style="width: 18%"| Files !! style="width: 82%"| Merge behaviour |- | '''mpmusic.txt, regions.txt, egates.txt''' || Applying merging to one of the files above will take any lines within the merge context and append them to the file, only if that line does not already exist in the file. |- | '''default aligments.txt, sounds.txt, locks.txt, properties.txt, map_XX.txt''' || Applies merging similarly to above, but takes key-value context into account. If a key doesn't exist in the file, the key-value pair will be appended to the file. If a key does exist in the file, then its value will be replaced by the new value in the merge context. |- | '''Room Settings files''' || Applies merging similarly to above, but certain keys have special handling. Effects, PlacedObjects, AmbientSounds, and Triggers will be merged additively, so the resulting room settings file will have all of the objects from the original room settings file, plus all of the new objects specified within the merge context. |- | '''world_XX files''' || Applies merging of world file contents in a CRS-style fashion. |- | '''short_strings file''' || Applying merging to a short_strings file will unencrypt the short_strings file, append any key-value pairs within the merge context if the key doesn't already exist (otherwise update the value to the new value), and then finally encrypt the short_strings file again. |- | '''anything else''' || Any other files not described above, will have their entire contents simply replaced with the contents of the merge context. |} b3b6fbd46b02c5faa7a123c3622ac338c1e93269 Downpour Reference/File Formats 0 147 276 2022-08-20T07:59:17Z Thalber 3 Port DPref/FileFormats wikitext text/x-wiki {{Cleanup}} Certain file formats have marginally changed in Downpour with the most common difference being that many things are now stored by value rather than by index. Some files also support new fields / attributes / parameters for new features. Most of these changes are optional and the files will still be parsed properly via backwards compatibility if still stored as indices, but updating may improve mod compatibility for the future. == locks.txt == This is the same, but &quot; : SWAPMAPSYMBOL&quot; can be added to the end of a line to swap the order that the two gate symbols appear on the in-game mini-map. == egates.txt == '''egates.txt''' is a new file in the same folder as locks.txt. Placing a gate room name as a new line in this file makes the gate an electric gate. == properties.txt == * Slugcats listed under Broken Shelters should be listed by name rather than index. (&quot;''Broken Shelters: '''<u>2</u>''': SL_S11''&quot; -&gt; &quot;''Broken Shelters: '''<u>Red</u>''': SL_S11''&quot;) * '''blackSalamanderChance''' is a new parameter that can be used to change the probability of salamanders in this region spawning as their dark variant. (Default: &quot;''blackSalamanderChance: 0.33''&quot;) * '''corruptionEffectColor''' is a new parameter than can be used to change the effect color of corruption objects and BLL creatures in the region. (Default &quot;''corruptionEffectColor: 0.0,0.0,1.0''&quot;) * '''corruptionEyeColor''' is a new parameter than can be used to change the eye color of corruption objects and BLL creatures in the region. (Default &quot;''corruptionEffectColor: 0.0,0.0,1.0''&quot;) * '''kelpColor''' is a new parameter that can be used to change the color of kelp creatures in the region. * '''albinos''' is a new parameter that can make relevant creautres spawn as their albino variants in a region. (Default &quot;albinos: false&quot;) * '''waterColorOverride''' is a new parameter that can change the color that water appears on the in-game minimap for the region. (Default &quot;''waterColorOverride: 0.05,0.05,0.8''&quot;) * '''earlyCycleChance''' is a new parameter that can set the probability of a pre-cycle event occurring at the start of a cycle in the region. (MSC only) * '''earlyCycleFloodChance''' is a new parameter that can set the probability of partial region flooding occuring during a pre-cycle event in this region. (MSC only) * '''scavsDelayInitialMin''' is a new parameter that sets the minimum time in ticks before a kill squad will be sent after a disliked player after entering this region. (default 4200) * '''scavsDelayInitialMax''' is a new parameter that sets the maximum time in ticks before a kill squad will be sent after a disliked player after entering this region. (default 8200) * '''scavsDelayRepeatMin''' is a new parameter that sets the minimum time in ticks before a support squad will be sent to a liked player after entering this region. (default 1100) * '''scavsDelayRepeatMax''' is a new parameter that sets the maximum time in ticks before a support squad will be sent to a liked player after entering this region. (default 1700) * Room_Attr lists attractiveness with Neutral,Forbidden,Avoid,Like,Stay instead of 0,1,2,3,4 respectively -- but it is optional to update this. Properties files can be suffixed by a slugcat name to make a region properties file exclusive to a specific slugcat campaign. (ie: properties-red.txt would apply the properties only while playing as Hunter). == map_xx.txt/map_xx.png == Map files can be suffixed by a slugcat name to make a map render exclusive to a specific slugcat campaign. (ie: map_xx-red.png) == displayname.txt == '''This file is required'''. This file contains a single line that contains the name of the region. This exists in the same folder as the properties / world_xx files. Display name files can also be provided that are suffixed by a slugcat name to change the name of the region for specific slugcat campaigns. (ie: displayname-red.txt) == world_xx.txt == Slugcat-specific spawn lines should be listed by name rather than index. (&quot;''('''<u>0,1</u>''')CC_A07 : 3-Mimic-{18}''&quot; -&gt; &quot;''('''<u>White,Yellow</u>''')CC_A07 : 3-Mimic-{18}''&quot;). A new &quot;CONDITIONAL LINKS&quot;/&quot;END CONDITIONAL LINKS&quot; section can be added before the &quot;ROOMS&quot;/&quot;END ROOMS&quot; section in the file to specify room connection changes that apply to specific slugcats. There are three types of conditional link lines: * '''SLUGCAT : HIDEROOM : ROOM''' - This excludes the given room from the region when playing as the specified slugcat(s). ** (Example) ''White,Yellow : HIDEROOM : SU_A99'' * '''SLUGCAT : EXCLUSIVEROOM : ROOM''' - This includes the given room in the region only when playing as the selected slugcat(s). ** (Example) ''White,Yellow : EXCLUSIVEROOM : SU_A99'' * '''SLUGCAT : TARGET_ROOM : CONNECTION_INDEX : NEW_CONNECTION_ROOM''' - This changes the given room connection in the target room to now connect to a different specified room while playing as the specified slugcat(s). To give an example for the last conditional link line type, imagine the following line existed in the ROOMS/END ROOMS section of the file: <pre>GW_A10 : GW_D01, GW_A07, GW_C06</pre> Then the following conditional links lines: <pre>White,Yellow : GW_A10 : 2 : DISCONNECTED White,Yellow : GW_A10 : 3 : GW_C07</pre> Would functionally transform the previous rooms line to the following when playing as Survivor or Monk: == room_settings.txt == Room settings files can be suffixed by a slugcat name to make a set of room settings exclusive to a specific slugcat campaign. (ie: su_c03_settings-red.txt)<br /> <br /> The following entities inside settings files now save by value rather than by index: * Any entities that use slugcat filter lists save the filter list by names rather than a binary flag. Importantly, the names listed are the slugcats who are ''excluded'' from the filter (ie: slugcats who would have had a 0 in the binary string). * Entities with filters include: ** Filter ** Unlock tokens (GoldToken/BlueToken) ** Trigger events (event&lt;tB&gt;) * For these filter lists, when multiple slugcats need to be excluded, their names should be separated by the | character. * '''DataPearl/UniqueDataPearl''': &quot;''UniqueDataPearl&gt;&lt;2550.05&gt;&lt;2104.999&gt;&lt;37~172~0~0~'''<u>14</u>'''~0''&quot; -&gt; &quot;''UniqueDataPearl&gt;&lt;2550.05&gt;&lt;2104.999&gt;&lt;37~172~0~0~'''<u>SL_moon</u>'''~0''&quot;. * The type field for '''StopMusicEvent''' uses AllSongs/SpecificSong/AllButSpecific instead of 0/1/2 respectively. == Threat Music metadata files == * Prefix an instrument in a layer with {D} to make it only play during the daytime (redundant/irrelevant if region doesn't use day-night cycles) * Prefix an instrument in a layer with {N} to make it only play during the nighttime (irrelevant if the region doesn't use day-night cycles) * Prefix an instrument in a layer with {M} to make it only play while the player is under the influence of mushrooms. * Prefix an instrument with a subregion name between {} to make it only play in that subregion. Multiple subregions can be specified by separating them with the | character. ** Example: ''{Five Pebbles (Recursive Transform Array)|Five Pebbles (Unfortunate Development)}TH_SS - NOISE'' == Short Strings == Each language has its own separate short strings file located at &quot;text_xxx/short_strings/strings.txt&quot;. Each line of this file is a Key|Value pair. 5d16cb3be2bdea4f14dcce52cca25be7b81da25b 282 276 2022-08-20T11:15:56Z Thalber 3 fix formatting wikitext text/x-wiki {{Cleanup}} Certain file formats have marginally changed in Downpour with the most common difference being that many things are now stored by value rather than by index. Some files also support new fields / attributes / parameters for new features. Most of these changes are optional and the files will still be parsed properly via backwards compatibility if still stored as indices, but updating may improve mod compatibility for the future. == locks.txt == This is the same, but " : SWAPMAPSYMBOL" can be added to the end of a line to swap the order that the two gate symbols appear on the in-game mini-map. == egates.txt == <code>egates.txt</code> is a new file in the same folder as locks.txt. Placing a gate room name as a new line in this file makes the gate an electric gate. == properties.txt == * Slugcats listed under Broken Shelters should be listed by name rather than index. (<code>Broken Shelters: <u>2</u>: SL_S11''"</code> -&gt; <code>Broken Shelters: <u>Red</u>: SL_S11</code>) * <code>blackSalamanderChance</code> is a new parameter that can be used to change the probability of salamanders in this region spawning as their dark variant. (Default: <code>blackSalamanderChance: 0.33</code>) * <code>corruptionEffectColor</code> is a new parameter than can be used to change the effect color of corruption objects and BLL creatures in the region. (Default <code>corruptionEffectColor: 0.0,0.0,1.0</code>) * <code>corruptionEyeColor</code> is a new parameter than can be used to change the eye color of corruption objects and BLL creatures in the region. (Default <code>corruptionEffectColor: 0.0,0.0,1.0</code>) * <code>kelpColor</code> is a new parameter that can be used to change the color of kelp creatures in the region. * <code>albinos</code> is a new parameter that can make relevant creautres spawn as their albino variants in a region. (Default <code>albinos: false</code>) * <code>waterColorOverride</code> is a new parameter that can change the color that water appears on the in-game minimap for the region. (Default <code>waterColorOverride: 0.05,0.05,0.8</code>) * <code>earlyCycleChance</code> is a new parameter that can set the probability of a pre-cycle event occurring at the start of a cycle in the region. (MSC only) * <code>earlyCycleFloodChance</code> is a new parameter that can set the probability of partial region flooding occuring during a pre-cycle event in this region. (MSC only) * <code>scavsDelayInitialMin</code> is a new parameter that sets the minimum time in ticks before a kill squad will be sent after a disliked player after entering this region. (default 4200) * <code>scavsDelayInitialMax</code> is a new parameter that sets the maximum time in ticks before a kill squad will be sent after a disliked player after entering this region. (default 8200) * <code>scavsDelayRepeatMin</code> is a new parameter that sets the minimum time in ticks before a support squad will be sent to a liked player after entering this region. (default 1100) * <code>scavsDelayRepeatMax</code> is a new parameter that sets the maximum time in ticks before a support squad will be sent to a liked player after entering this region. (default 1700) * Room_Attr lists attractiveness with <code>Neutral,Forbidden,Avoid,Like,Stay</code> instead of <code>0,1,2,3,4</code> respectively -- but it is optional to update this. Properties files can be suffixed by a slugcat name to make a region properties file exclusive to a specific slugcat campaign. (ie: properties-red.txt would apply the properties only while playing as Hunter). == map_xx.txt/map_xx.png == Map files can be suffixed by a slugcat name to make a map render exclusive to a specific slugcat campaign. (ie: <code>map_xx-red.png</code>) == displayname.txt == '''This file is required'''. This file contains a single line that contains the name of the region. This exists in the same folder as the properties / world_xx files. Display name files can also be provided that are suffixed by a slugcat name to change the name of the region for specific slugcat campaigns. (ie: <code>displayname-red.txt</code>) == world_xx.txt == Slugcat-specific spawn lines should be listed by name rather than index. (<code>(<u>0,1</u>)CC_A07 : 3-Mimic-{18}</code> -&gt; <code>(<u>White,Yellow</u>)CC_A07 : 3-Mimic-{18}</code>). A new "CONDITIONAL LINKS"/"END CONDITIONAL LINKS" section can be added before the "ROOMS"/"END ROOMS" section in the file to specify room connection changes that apply to specific slugcats. There are three types of conditional link lines: * <code>SLUGCAT : HIDEROOM : ROOM</code> - This excludes the given room from the region when playing as the specified slugcat(s). ** (Example) <code>White,Yellow : HIDEROOM : SU_A99</code> * <code>SLUGCAT : EXCLUSIVEROOM : ROOM</code> - This includes the given room in the region only when playing as the selected slugcat(s). ** (Example) <code>White,Yellow : EXCLUSIVEROOM : SU_A99</code> * <code>SLUGCAT : TARGET_ROOM : CONNECTION_INDEX : NEW_CONNECTION_ROOM</code> - This changes the given room connection in the target room to now connect to a different specified room while playing as the specified slugcat(s). To give an example for the last conditional link line type, imagine the following line existed in the ROOMS/END ROOMS section of the file: <pre>GW_A10 : GW_D01, GW_A07, GW_C06</pre> Then the following conditional links lines: <pre>White,Yellow : GW_A10 : 2 : DISCONNECTED White,Yellow : GW_A10 : 3 : GW_C07</pre> Would functionally transform the previous rooms line to the following when playing as Survivor or Monk: == room_settings.txt == Room settings files can be suffixed by a slugcat name to make a set of room settings exclusive to a specific slugcat campaign. (ie: <code>su_c03_settings-red.txt</code>) The following entities inside settings files now save by value rather than by index: * Any entities that use slugcat filter lists save the filter list by names rather than a binary flag. Importantly, the names listed are the slugcats who are ''excluded'' from the filter (ie: slugcats who would have had a 0 in the binary string). * Entities with filters include: ** Filter ** Unlock tokens (GoldToken/BlueToken) ** Trigger events (<code>event&lt;tB&gt;</code>) * For these filter lists, when multiple slugcats need to be excluded, their names should be separated by the | character. * <code>DataPearl/UniqueDataPearl</code>: <code>UniqueDataPearl&gt;&lt;2550.05&gt;&lt;2104.999&gt;&lt;37~172~0~0~<u>14</u>~0</code> -&gt; <code>UniqueDataPearl&gt;&lt;2550.05&gt;&lt;2104.999&gt;&lt;37~172~0~0~<u>SL_moon</u>~0</code>. * The type field for <code>StopMusicEvent</code> uses <code>AllSongs/SpecificSong/AllButSpecific</code> instead of <code>0/1/2</code> respectively. == Threat Music metadata files == * Prefix an instrument in a layer with {D} to make it only play during the daytime (redundant/irrelevant if region doesn't use day-night cycles) * Prefix an instrument in a layer with {N} to make it only play during the nighttime (irrelevant if the region doesn't use day-night cycles) * Prefix an instrument in a layer with {M} to make it only play while the player is under the influence of mushrooms. * Prefix an instrument with a subregion name between <code>{}</code> to make it only play in that subregion. Multiple subregions can be specified by separating them with the pipe character (<code>|</code>). ** Example: <code>{Five Pebbles (Recursive Transform Array)|Five Pebbles (Unfortunate Development)}TH_SS - NOISE''</code> == Short Strings == Each language has its own separate short strings file located at <code>text_xxx/short_strings/strings.txt</code>. Each line of this file is a Key|Value pair. 516d50d04eefd8b27f6e67990f63271e1482b4cb 283 282 2022-08-20T11:16:28Z Thalber 3 wikitext text/x-wiki Certain file formats have marginally changed in Downpour with the most common difference being that many things are now stored by value rather than by index. Some files also support new fields / attributes / parameters for new features. Most of these changes are optional and the files will still be parsed properly via backwards compatibility if still stored as indices, but updating may improve mod compatibility for the future. == locks.txt == This is the same, but " : SWAPMAPSYMBOL" can be added to the end of a line to swap the order that the two gate symbols appear on the in-game mini-map. == egates.txt == <code>egates.txt</code> is a new file in the same folder as locks.txt. Placing a gate room name as a new line in this file makes the gate an electric gate. == properties.txt == * Slugcats listed under Broken Shelters should be listed by name rather than index. (<code>Broken Shelters: <u>2</u>: SL_S11''"</code> -&gt; <code>Broken Shelters: <u>Red</u>: SL_S11</code>) * <code>blackSalamanderChance</code> is a new parameter that can be used to change the probability of salamanders in this region spawning as their dark variant. (Default: <code>blackSalamanderChance: 0.33</code>) * <code>corruptionEffectColor</code> is a new parameter than can be used to change the effect color of corruption objects and BLL creatures in the region. (Default <code>corruptionEffectColor: 0.0,0.0,1.0</code>) * <code>corruptionEyeColor</code> is a new parameter than can be used to change the eye color of corruption objects and BLL creatures in the region. (Default <code>corruptionEffectColor: 0.0,0.0,1.0</code>) * <code>kelpColor</code> is a new parameter that can be used to change the color of kelp creatures in the region. * <code>albinos</code> is a new parameter that can make relevant creautres spawn as their albino variants in a region. (Default <code>albinos: false</code>) * <code>waterColorOverride</code> is a new parameter that can change the color that water appears on the in-game minimap for the region. (Default <code>waterColorOverride: 0.05,0.05,0.8</code>) * <code>earlyCycleChance</code> is a new parameter that can set the probability of a pre-cycle event occurring at the start of a cycle in the region. (MSC only) * <code>earlyCycleFloodChance</code> is a new parameter that can set the probability of partial region flooding occuring during a pre-cycle event in this region. (MSC only) * <code>scavsDelayInitialMin</code> is a new parameter that sets the minimum time in ticks before a kill squad will be sent after a disliked player after entering this region. (default 4200) * <code>scavsDelayInitialMax</code> is a new parameter that sets the maximum time in ticks before a kill squad will be sent after a disliked player after entering this region. (default 8200) * <code>scavsDelayRepeatMin</code> is a new parameter that sets the minimum time in ticks before a support squad will be sent to a liked player after entering this region. (default 1100) * <code>scavsDelayRepeatMax</code> is a new parameter that sets the maximum time in ticks before a support squad will be sent to a liked player after entering this region. (default 1700) * Room_Attr lists attractiveness with <code>Neutral,Forbidden,Avoid,Like,Stay</code> instead of <code>0,1,2,3,4</code> respectively -- but it is optional to update this. Properties files can be suffixed by a slugcat name to make a region properties file exclusive to a specific slugcat campaign. (ie: properties-red.txt would apply the properties only while playing as Hunter). == map_xx.txt/map_xx.png == Map files can be suffixed by a slugcat name to make a map render exclusive to a specific slugcat campaign. (ie: <code>map_xx-red.png</code>) == displayname.txt == '''This file is required'''. This file contains a single line that contains the name of the region. This exists in the same folder as the properties / world_xx files. Display name files can also be provided that are suffixed by a slugcat name to change the name of the region for specific slugcat campaigns. (ie: <code>displayname-red.txt</code>) == world_xx.txt == Slugcat-specific spawn lines should be listed by name rather than index. (<code>(<u>0,1</u>)CC_A07 : 3-Mimic-{18}</code> -&gt; <code>(<u>White,Yellow</u>)CC_A07 : 3-Mimic-{18}</code>). A new "CONDITIONAL LINKS"/"END CONDITIONAL LINKS" section can be added before the "ROOMS"/"END ROOMS" section in the file to specify room connection changes that apply to specific slugcats. There are three types of conditional link lines: * <code>SLUGCAT : HIDEROOM : ROOM</code> - This excludes the given room from the region when playing as the specified slugcat(s). ** (Example) <code>White,Yellow : HIDEROOM : SU_A99</code> * <code>SLUGCAT : EXCLUSIVEROOM : ROOM</code> - This includes the given room in the region only when playing as the selected slugcat(s). ** (Example) <code>White,Yellow : EXCLUSIVEROOM : SU_A99</code> * <code>SLUGCAT : TARGET_ROOM : CONNECTION_INDEX : NEW_CONNECTION_ROOM</code> - This changes the given room connection in the target room to now connect to a different specified room while playing as the specified slugcat(s). To give an example for the last conditional link line type, imagine the following line existed in the ROOMS/END ROOMS section of the file: <pre>GW_A10 : GW_D01, GW_A07, GW_C06</pre> Then the following conditional links lines: <pre>White,Yellow : GW_A10 : 2 : DISCONNECTED White,Yellow : GW_A10 : 3 : GW_C07</pre> Would functionally transform the previous rooms line to the following when playing as Survivor or Monk: == room_settings.txt == Room settings files can be suffixed by a slugcat name to make a set of room settings exclusive to a specific slugcat campaign. (ie: <code>su_c03_settings-red.txt</code>) The following entities inside settings files now save by value rather than by index: * Any entities that use slugcat filter lists save the filter list by names rather than a binary flag. Importantly, the names listed are the slugcats who are ''excluded'' from the filter (ie: slugcats who would have had a 0 in the binary string). * Entities with filters include: ** Filter ** Unlock tokens (GoldToken/BlueToken) ** Trigger events (<code>event&lt;tB&gt;</code>) * For these filter lists, when multiple slugcats need to be excluded, their names should be separated by the | character. * <code>DataPearl/UniqueDataPearl</code>: <code>UniqueDataPearl&gt;&lt;2550.05&gt;&lt;2104.999&gt;&lt;37~172~0~0~<u>14</u>~0</code> -&gt; <code>UniqueDataPearl&gt;&lt;2550.05&gt;&lt;2104.999&gt;&lt;37~172~0~0~<u>SL_moon</u>~0</code>. * The type field for <code>StopMusicEvent</code> uses <code>AllSongs/SpecificSong/AllButSpecific</code> instead of <code>0/1/2</code> respectively. == Threat Music metadata files == * Prefix an instrument in a layer with {D} to make it only play during the daytime (redundant/irrelevant if region doesn't use day-night cycles) * Prefix an instrument in a layer with {N} to make it only play during the nighttime (irrelevant if the region doesn't use day-night cycles) * Prefix an instrument in a layer with {M} to make it only play while the player is under the influence of mushrooms. * Prefix an instrument with a subregion name between <code>{}</code> to make it only play in that subregion. Multiple subregions can be specified by separating them with the pipe character (<code>|</code>). ** Example: <code>{Five Pebbles (Recursive Transform Array)|Five Pebbles (Unfortunate Development)}TH_SS - NOISE''</code> == Short Strings == Each language has its own separate short strings file located at <code>text_xxx/short_strings/strings.txt</code>. Each line of this file is a Key|Value pair. 5ae0c3caaaaa3c5a8153d0eaae557c676b669d32 Downpour Reference/BepInEx Files 0 148 277 2022-08-20T08:01:19Z Thalber 3 Port DPref/BixFiles wikitext text/x-wiki {{Cleanup}} DLL files are stored in and loaded directly from the mod folders. This page describes how BepInEx is handled in Downpour. == Directory Structure == === Toggleable DLLs === The DLL files for your mod will go within a cooresponding location in your mod's folder. DLL files included this way can be toggled on and off using the in-game REMIX menu. DLL files can be called any name, but need to be placed into the following folders to be recognized: * ''your-mod-folder/plugins/*.dll'' ** Location for any BepInPlugins. * ''your-mod-folder/patchers/*.dll'' ** Location for any patch mods. Note that Downpour does not attempt to hot-reload DLL mods. If a mod is toggled on or off in the REMIX menu that contains a DLL file, the game will force a relaunch to finish the mod applying process. == Mod Lifecycle Functions == The following lifecycle functions exist in the RainWorld class that can be useful for initializing/uninitializing, loading/unloading resources for your mod when it is toggled on and off. * '''OnModsInit()''': Called when the game is first launched if your mod is one of the enabled mods. Also called any time mods are applied in the REMIX menu if your mod is one of the enabled mods. Because it is called any time the apply button is pressed, expect that this function can be called multiple times in a single game session, so provide checks to ensure you are not double-loading resources if it is called again. * '''PreModsInit()''': Called right before the OnModsInit() function. * '''PostModsInit()''': Called right after the OnModsInit() function. * '''OnModsEnabled()''': Unlike the init function, this is not called when the game is launched. It is called when mods are applied in the REMIX menu, if your mod is now enabled, but ''only'' if it was previously disabled. This is unlike the init function which will be called whenever your mod is enabled even if it was previously enabled as well. This function recieves an argument which contains a list of all newly enabled mods that weren't previously enabled. * '''OnModsDisabled()''': The opposite of the above function. Called when mods are applied in the REMIX menu, if the mod is now disabled, but ''only'' if it was previously enabled. This function recieves an argument which contains a list of all newly disabled mods that were previously enabled. * '''PreModsDisabledEnabled()''': Called before any of the enabled/disabled/init functions are called. Only part of the apply mods workflow; does not get called on game launch. * '''PostModsDisabledEnabled()''': Called after all of the enabled/disabled/init functions are finished being called. Only part of the apply mods workflow; does not get called on game launch. == Utility Files == For convenience, the following Assembly-CSharp associated files are automatically generated and available for use: * '''BepInEx/utils/HOOKS-Assembly-CSharp.dll''' ** Hookgen for Assembly-CSharp * '''BepInEx/utils/PUBLIC-Assembly-CSharp.dll''' ** Assembly-CSharp with all members public c026f268bb76582f26c145b160e787a578cf5cee 285 277 2022-08-20T12:12:41Z Thalber 3 wikitext text/x-wiki DLL files are stored in and loaded directly from the mod folders. This page describes how BepInEx is handled in Downpour. == Directory Structure == === Toggleable DLLs === The DLL files for your mod will go within a cooresponding location in your mod's folder. DLL files included this way can be toggled on and off using the in-game REMIX menu. DLL files can be called any name, but need to be placed into the following folders to be recognized: * <code>your-mod-folder/plugins/*.dll</code> - Location for any BepInPlugins. * <code>your-mod-folder/patchers/*.dll</code> - Location for any patch mods. Note that Downpour does not attempt to hot-reload DLL mods. If a mod is toggled on or off in the REMIX menu that contains a DLL file, the game will force a relaunch to finish the mod applying process. == Mod Lifecycle Functions == The following lifecycle functions exist in the RainWorld class that can be useful for initializing/uninitializing, loading/unloading resources for your mod when it is toggled on and off. {|class="wikitable" ! style="width: 10%" | Method !! style="width: 90%" | Meaning |- | '''OnModsInit()''' || Called when the game is first launched if your mod is one of the enabled mods. Also called any time mods are applied in the REMIX menu if your mod is one of the enabled mods. Because it is called any time the apply button is pressed, expect that this function can be called multiple times in a single game session, so provide checks to ensure you are not double-loading resources if it is called again. |- | '''PreModsInit()''' || Called right before the OnModsInit() function. |- | '''PostModsInit()''' || Called right after the OnModsInit() function. |- | '''OnModsEnabled()''' || Unlike the init function, this is not called when the game is launched. It is called when mods are applied in the REMIX menu, if your mod is now enabled, but ''only'' if it was previously disabled. This is unlike the init function which will be called whenever your mod is enabled even if it was previously enabled as well. This function recieves an argument which contains a list of all newly enabled mods that weren't previously enabled. |- | '''OnModsDisabled()''' || The opposite of the above function. Called when mods are applied in the REMIX menu, if the mod is now disabled, but ''only'' if it was previously enabled. This function recieves an argument which contains a list of all newly disabled mods that were previously enabled. |- | '''PreModsDisabledEnabled()''' || Called before any of the enabled/disabled/init functions are called. Only part of the apply mods workflow; does not get called on game launch. |- | '''PostModsDisabledEnabled()''' || Called after all of the enabled/disabled/init functions are finished being called. Only part of the apply mods workflow; does not get called on game launch. |} == Utility Files == For convenience, the following Assembly-CSharp associated files are automatically generated and available for use: * <code>BepInEx/utils/HOOKS-Assembly-CSharp.dll</code> - Hookgen for Assembly-CSharp * <code>BepInEx/utils/PUBLIC-Assembly-CSharp.dll</code> - Assembly-CSharp with all members public fc6c60aa7f247716945cfb81d16b097051c84b22 Downpour Reference/ExtEnum 0 149 278 2022-08-20T08:04:22Z Thalber 3 Created page with "{{Cleanup}} ExtEnum is a new data structure in Downpour that is used in place of most enums in the source code, and is designed for better mod compatibility and easy run-time modification of its values. == Extending Existing ExtEnums == The recommended procedure for having your mod extend the entries for existing enum values is to create a new static class within your mod's code that includes the new entries for the enum. This new static class has three goals: * Add..." wikitext text/x-wiki {{Cleanup}} ExtEnum is a new data structure in Downpour that is used in place of most enums in the source code, and is designed for better mod compatibility and easy run-time modification of its values. == Extending Existing ExtEnums == The recommended procedure for having your mod extend the entries for existing enum values is to create a new static class within your mod's code that includes the new entries for the enum. This new static class has three goals: * Add the new entries to the enum when your mod is enabled. * Remove the new entries from the enum when your mod is disabled. * Provide a way to reference the new entries you added. Below is an example of how this might look. The below static class is built to add two new entries to the original game's CreatureTemplate.Type enum: <syntaxhighlight lang="c#"> public class MyModdedEnums { public class CreatureTemplateType { public static CreatureTemplate.Type NewCreature; public static CreatureTemplate.Type AnotherNewCreature; public static void RegisterValues() { NewCreature = new CreatureTemplate.Type("NewCreature", true); AnotherNewCreature = new CreatureTemplate.Type("AnotherNewCreature", true); } public static void UnregisterValues() { if (NewCreature != null) { NewCreature.Unregister(); NewCreature = null; } if (AnotherNewCreature != null) { AnotherNewCreature.Unregister(); AnotherNewCreature = null; } } } } </syntaxhighlight> '''MyModdedEnums.CreatureTemplateType.RegisterValues()''' would be called on the mod being enabled. '''MyModdedEnums.CreatureTemplateType.UnregisterValues()''' would be called on the mod being disabled. To reference one of the new entries anywhere in the code where a CreatureTemplate.Type value is accepted, you can reference it with the static fields defined in your class, like with '''MyModdedEnums.CreatureTemplateType.NewCreature'''. == Creating New ExtEnums == Whereas a normal enum definition would look like: <syntaxhighlight lang="c#"> public enum Test { Hello, World, Slug, Cat }; </syntaxhighlight> The equivalent construction for an ExtEnum would look like: <syntaxhighlight lang="c#"> public class Test : ExtEnum<Test> { public static readonly Test Hello = new Test("Hello", true); public static readonly Test World = new Test("World", true); public static readonly Test Slug = new Test("Slug", true); public static readonly Test Cat = new Test("Cat", true); public Test(string value, bool register=false) : base(value, register) {} } </syntaxhighlight> Additionally, add a reference to your new enum into the '''ExtEnumInitializer.InitTypes()''' function to ensure the static entries are populated into memory before they are accessed. == Rewriting Existing Enum Code == For Enum.GetNames(), the code: <syntaxhighlight lang="c#"> for (int i=0; i<Enum.GetNames(typeof(EnumType)).Length; i++) { string name = Enum.GetNames(typeof(EnumType))[i]; } </syntaxhighlight> Becomes: <syntaxhighlight lang="c#"> for (int i=0; i<EnumType.values.Count; i++) { string name = EnumType.values.entries[i]; } </syntaxhighlight> For Custom.ParseEnum() or Enum.Parse(), the code: <syntaxhighlight lang="c#"> EnumType parsedEnum = Custom.ParseEnum<EnumType>(stringValue); </syntaxhighlight> Becomes: <syntaxhighlight lang="c#"> EnumType parsedEnum = new EnumType(stringValue); </syntaxhighlight> Although note for the above that if stringValue is not a registered type for the enum, instead of throwing an exception, this will create an ExtEnum object whose Index value is -1. Enum variables that were defined as nullable before shouldn't specify the ? operator anymore, as ExtEnums can be null by default. == Collision Detection == As long as you give your enum entries sufficiently unique names, the chance of another mod adding a new entry to the same enum with the same name is low. But if you want to play it safe and write your code to be completely robust to name conflicts, you can check if the name exists before registering the enum value and adapt accordingly. For example: <syntaxhighlight lang="c#"> public static void RegisterValues() { string entryName = "NewCreature"; int conflictIndex = 1; while (CreatureTemplate.Type.values.entries.Contains(entryName)) { conflictIndex += 1; entryName = "NewCreature" + conflictIndex.ToString(); } NewCreature = new CreatureTemplate.Type(entryName, true); } </syntaxhighlight> 3aaeb93e288ddb5c55e08ec0dc0d7b122d67d01c 286 278 2022-08-20T12:17:48Z Thalber 3 fix formatting wikitext text/x-wiki ExtEnum is a new data structure in Downpour that is used in place of most enums in the source code, and is designed for better mod compatibility and easy run-time modification of its values. == Extending Existing ExtEnums == The recommended procedure for having your mod extend the entries for existing enum values is to create a new static class within your mod's code that includes the new entries for the enum. This new static class has three goals: * Add the new entries to the enum when your mod is enabled. * Remove the new entries from the enum when your mod is disabled. * Provide a way to reference the new entries you added. Below is an example of how this might look. The below static class is built to add two new entries to the original game's CreatureTemplate.Type enum: <syntaxhighlight lang="c#"> public class MyModdedEnums { public class CreatureTemplateType { public static CreatureTemplate.Type NewCreature; public static CreatureTemplate.Type AnotherNewCreature; public static void RegisterValues() { NewCreature = new CreatureTemplate.Type("NewCreature", true); AnotherNewCreature = new CreatureTemplate.Type("AnotherNewCreature", true); } public static void UnregisterValues() { if (NewCreature != null) { NewCreature.Unregister(); NewCreature = null; } if (AnotherNewCreature != null) { AnotherNewCreature.Unregister(); AnotherNewCreature = null; } } } } </syntaxhighlight> <code>MyModdedEnums.CreatureTemplateType.RegisterValues()</code> would be called on the mod being enabled. <code>MyModdedEnums.CreatureTemplateType.UnregisterValues()</code> would be called on the mod being disabled. To reference one of the new entries anywhere in the code where a CreatureTemplate.Type value is accepted, you can reference it with the static fields defined in your class, like with <code>MyModdedEnums.CreatureTemplateType.NewCreature</code>. == Creating New ExtEnums == Whereas a normal enum definition would look like: <syntaxhighlight lang="c#"> public enum Test { Hello, World, Slug, Cat }; </syntaxhighlight> The equivalent construction for an ExtEnum would look like: <syntaxhighlight lang="c#"> public class Test : ExtEnum<Test> { public static readonly Test Hello = new Test("Hello", true); public static readonly Test World = new Test("World", true); public static readonly Test Slug = new Test("Slug", true); public static readonly Test Cat = new Test("Cat", true); public Test(string value, bool register=false) : base(value, register) {} } </syntaxhighlight> Additionally, add a reference to your new enum into the <code>ExtEnumInitializer.InitTypes()</code> function to ensure the static entries are populated into memory before they are accessed. == Rewriting Existing Enum Code == For Enum.GetNames(), the code: <syntaxhighlight lang="c#"> for (int i = 0; i<Enum.GetNames(typeof(EnumType)).Length; i++) { string name = Enum.GetNames(typeof(EnumType))[i]; } </syntaxhighlight> Becomes: <syntaxhighlight lang="c#"> for (int i = 0; i < EnumType.values.Count; i++) { string name = EnumType.values.entries[i]; } </syntaxhighlight> For <code>Custom.ParseEnum()</code> or <code>Enum.Parse()</code>, the code: <syntaxhighlight lang="c#"> EnumType parsedEnum = Custom.ParseEnum<EnumType>(stringValue); </syntaxhighlight> Becomes: <syntaxhighlight lang="c#"> EnumType parsedEnum = new EnumType(stringValue); </syntaxhighlight> Although note for the above that if stringValue is not a registered type for the enum, instead of throwing an exception, this will create an ExtEnum object whose Index value is -1. Enum variables that were defined as nullable before shouldn't specify the ? operator anymore, as ExtEnums can be null by default. == Collision Detection == As long as you give your enum entries sufficiently unique names, the chance of another mod adding a new entry to the same enum with the same name is low. But if you want to play it safe and write your code to be completely robust to name conflicts, you can check if the name exists before registering the enum value and adapt accordingly. For example: <syntaxhighlight lang="c#"> public static void RegisterValues() { string entryName = "NewCreature"; int conflictIndex = 1; while (CreatureTemplate.Type.values.entries.Contains(entryName)) { conflictIndex += 1; entryName = "NewCreature" + conflictIndex.ToString(); } NewCreature = new CreatureTemplate.Type(entryName, true); } </syntaxhighlight> ee4ad424843a4dd4f2c3994d088a984c0902175b Downpour Reference/Conflict Merging 0 150 279 2022-08-20T08:06:43Z Thalber 3 Port DPref/ConflictMerging wikitext text/x-wiki This page describes how file conflicts are resolved when multiple mods try to modify the same files. == MergedMods Folder == When one or more [[Downpour_Reference/Modification_Files|Modification files]] are applied to a file, the new resulting contents of the file after all modifications have been applied is generated and stored into a new folder called &quot;'''mergedmods'''&quot;, located in StreamingAssets. Similarly to the patterns we've seen before, the contents of the mergedmods folder is a mirror of the directory structure of the rest of the game. So for example, if a modification file is applied to:<br /> <br />      &quot;''Assets/StreamingAssets/world/regions/regions.txt''&quot;<br /> <br /> then the result will wind up at:<br /> <br />      &quot;''Assets/StreamingAssets/mergedmods/world/regions/regions.txt''&quot;<br /> <br /> The full contents of the mergedmods folder are cleared and regenerated any time mods are applied through the REMIX menu. == Load Order == The load order of mods dictates how modifications and merges are applied, and can affect the end result of the mergedmods folder. Load order is applied in the following way, in the following order: # When the game is first launched, any DLL mods from the mods folders will be loaded in load order. # Once mods are applied, first all full-file content overwrite actions are applied, in load order. # Once all overwrites are done, next all merge actions from modification files are applied, in load order. # Finally, once all merge actions are done, all remaining non-merge actions from modification files are applied, in load order. == Checksum == Whenever the game launches, the checksum of all installed mods is generated. By default, the checksum for a mod will be determined from the contents of all files contained in the mod's folder, excluding the modinfo JSON file. There is an optional parameter in the modinfo file that if specified, will skip this style of checksum generation, and will instead just use the mod's current version number as its checksum. If on game launch, the mod's checksum has changed since the last launch of the game (for example, an update for the mod was released and downloaded via Steam Workshop), then the typical apply mods process that is normally done through the REMIX menu will automatically get triggered on game launch, and will force the updated mod(s) to get applied again. This will regenerate the mergedmods folder along with any other typical actions that get performed during the apply mods process. ad70ecfa45440d651b8ccf8ab41e981162cd4786 287 279 2022-08-20T12:20:39Z Thalber 3 fix formatting wikitext text/x-wiki This page describes how file conflicts are resolved when multiple mods try to modify the same files. == MergedMods Folder == When one or more [[Downpour_Reference/Modification_Files|Modification files]] are applied to a file, the new resulting contents of the file after all modifications have been applied is generated and stored into a new folder called <code>mergedmods</code>, located in StreamingAssets. Similarly to the patterns we've seen before, the contents of the mergedmods folder is a mirror of the directory structure of the rest of the game. So for example, if a modification file is applied to: : <code>Assets/StreamingAssets/world/regions/regions.txt</code> then the result will wind up at: : <code>Assets/StreamingAssets/mergedmods/world/regions/regions.txt</code> The full contents of the mergedmods folder are cleared and regenerated any time mods are applied through the REMIX menu. == Load Order == The load order of mods dictates how modifications and merges are applied, and can affect the end result of the mergedmods folder. Load order is applied in the following way, in the following order: # When the game is first launched, any DLL mods from the mods folders will be loaded in load order. # Once mods are applied, first all full-file content overwrite actions are applied, in load order. # Once all overwrites are done, next all merge actions from modification files are applied, in load order. # Finally, once all merge actions are done, all remaining non-merge actions from modification files are applied, in load order. == Checksum == Whenever the game launches, the checksum of all installed mods is generated. By default, the checksum for a mod will be determined from the contents of all files contained in the mod's folder, excluding the modinfo JSON file. There is an optional parameter in the modinfo file that if specified, will skip this style of checksum generation, and will instead just use the mod's current version number as its checksum. If on game launch, the mod's checksum has changed since the last launch of the game (for example, an update for the mod was released and downloaded via Steam Workshop), then the typical apply mods process that is normally done through the REMIX menu will automatically get triggered on game launch, and will force the updated mod(s) to get applied again. This will regenerate the mergedmods folder along with any other typical actions that get performed during the apply mods process. d52376227393aa86a4f7efda296bba58c17bc340 Dev Tools 0 84 288 215 2022-08-20T12:56:15Z Thalber 3 /* Interface Tabs */ wrap tabber wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ==Interface Tabs== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. <div class="wikitable"><tabber> |-| Room settings= This tab mostly contains settings for base room visuals, such as palette, cloud cover and terrain wetness. === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === [[File:Fadepalette example.png]] ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image on the right shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! {|class="wikitable" |- ! '''Effect''' !! '''Description''' |- | SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. |- | SkyBloom || Increases how fuzzy/bloomy the sky's light is. |- | LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. |- | Bloom || Similar to SkyBloom, but applies to lights. |- | Fog || Creates a white cloudy effect at layer 1. Not compatible with |- | Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- |- | GreenSparks || Underhang, and the Legs' green sparkles. |- | VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | Flies || Spawns small flys that buzz around the room and land on objects. |- | FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | TinyDragonFly || Spawns tiny bugs that fly around plants. |- | RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | Ant || Spawns small jumping bugs. |- | Beetle || Spawns small beetles that slowly fly around the room. |- | WaterGlowWorm || Spawns small worms that swim around in water. |- | Wasp || Spawns small wasps that quickly dart between walls. |- | Moth || Spawns small white moths which slowly flutter around the room. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom`, VoidMelt </syntaxhighlight> |-| Objects= Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds= [[File:soundTab.png|400px|right|border|]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map= {{todo|target=tab}} [[File:mapTab.png|400px|right|border|]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections.png|400px|right|border|Connections on dev map]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png|400px|right|border|Canon view of the map]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png|400px|right|border|Example of a rendered map .png file]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers= {{todo|target=tab}} [[File:triggerTab.png|600px|right|border|Trigger tab view]] <span id="general-controls"></span> == General controls == === Save === Saves the current effects and room settings to a file inside the region’s World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by pressing R and returning to the room to see the changes. === Inherent from template === Will set the values stored in a specific template the region has to this room. === Save as template: === Saves the current room’s settings as a template for easy re-use. == Triggers Menu == '''Triggers''' are the mechanism in which some in-game events occur, such as specific songs playing, projections being displayed by the player guide overseer, or information text being displayed at the bottom of the screen. Clicking one of the four options in the bottom right-hand box will place a trigger of that type, which can be moved just like other devtools objects. === Trigger Options === Triggers have a number of settings which determine what the trigger does and under what circumstances. {| class="wikitable" |+ |- ! Trigger setting !! Description |- | Active from cycle || The minimum total cycle requirement for the trigger to activate. |- | Active up to cycle || The maximum cycle limit for the trigger to activate - if the player has a cycle count higher than this number, the trigger will not activate. |- | Fire chance || A random percentage chance for the trigger to activate, from 0% to 100%. |- | Trigger delay || How many seconds between the requirements for the trigger being met and the event occurring. |- | Karma req || The minimum karma the player needs for the trigger to activate (from 0 to 5) |- | Can only fire once/Can fire multiple times || Self-explanatory, determines whether the trigger only fires once or not. |- | No entrance requirement/Entrance XX || Determines whether the player can enter from any entrance pipe, or whether they need to come through a specific one. When an entrance is selected, a red line will connect this entrance and the options box. |- | White, Yellow, Red || Determines which gamemodes the trigger fires on - Survivor, Hunter or Monk. A gamemode’s name being displayed means that the trigger will fire in said gamemode. |} === Event Types === The lowest button on the options box lets you pick what type of event you want to add. ==== MusicEvent ==== Plays a song from the soundtrack. * The first button lets you pick the song you want to play. Files for these songs can be found in *Rain World, or many of them can be found [https://www.youtube.com/playlist?list=PLPJWSVeszYFBo1oAXYgzGfJfewnGKgGna online.] {| class="wikitable" |+ MusicEvent options |- ! Option !! Description |- | Play volume || The volume the song plays at. |- | Fade in || In seconds, how long the song takes to reach full volume. |- | Song priority || If this song’s priority is higher than another’s, then this song will continue to play if the other trigger is activated. If the priority is lower, then the higher one will play instead of it. |- | Drone volume || WIP, presumably adds a background drone sound at the set volume. |- | Fade out at threat || The threat level at which the song fades out and is overtaken by the threat music. |- | Rest cycles || If this trigger can activate multiple times, the number of cycles for the trigger to wait before being able to fire again. |- | Room transitions || How many rooms the song will continue playing through. |- | One song per cycle || Whether or not the same song can activate multiple times in one cycle. |- | Play once/loop || Determines whether the song plays once or loops |- | Continue at death || Continue playing the song when the player dies. |- | Continue through gate || Continue playing the song when the player uses a region gate. |} ==== StopMusicEvent ==== As the name says, stops one or more MusicEvents. The first button lets you pick the song you want to stop/exclude. * '''Priority:''' If a song has a higher priority than the trigger, it won’t stop. * '''Fade out:''' Same as fade in, but fading out to silence. * '''Stop all songs/stop specific song/stop all but specific song:''' Self-explanatory, song selected at the top of the box is what this refers to. ==== '''PoleMimicSubtleReveal''' ==== Causes a pole mimic to flutter slightly when activated. ==== '''ShowProjectedImageEvent''' ==== Shows player guide overseer projections ==== '''RoomSpecificTextMessage''' ==== Causes specific text prompt to appear. Prompts are hardcoded by room name {{Cn}} ==== '''BringPlayerGuideToRoom''' ==== Forces player overseer to current room === Trigger Types === * '''Spot:''' The most commonly used trigger; activates when slugcat walks into a specific circular area of the room. This is indicated by a white area-of-effect which can be moved and scaled. * '''SeeCreature:''' ''WIP, presumably activates upon a certain creature being seen.'' * '''RegionBump:''' Activates either when the region is entered or at the beginning of a cycle where the region name and cycle count is shown. * '''PreRegionBump:''' Seemingly functions the same way as RegionBump. </tabber> </div> [[Category:Dev Tools]] a588f9fcaecc27b46e01cb0780929979d33a53e8 Category:Pages with broken file links 14 151 289 2022-08-20T13:02:00Z Thalber 3 Created page with "This category contains pages linking to nonexistent files." wikitext text/x-wiki This category contains pages linking to nonexistent files. 7cbb25b375877e410b81072ac5e4678ed0b0650a Category:Pages using Tabber parser tag 14 152 290 2022-08-20T13:02:41Z Thalber 3 Created page with "This category contains pages with tabbers." wikitext text/x-wiki This category contains pages with tabbers. 8f46d924d7e9d9c7c468a65be13bca938fcfcb77 Template:Cleanup 10 88 292 246 2022-08-20T13:39:35Z Thalber 3 trim wikitext text/x-wiki <includeonly><div class="nomobile">{{Ambox | image = <p><span style="margin-right:15px>[[File:Hardhatcat.png|middle|47px]]</span> | type = '''Cleanup needed''' | info = This article needs structural or tonal clean-up to meet quality standards. Feel free to help {{fullurl|{{FULLPAGENAME}}|action=edit{{#if: {{{1|}}} | &section={{{1}}} }}|text=improve}} it.</p> | border = gray }}[[Category:Cleanup needed]]</div> </includeonly> <noinclude> Usage: <nowiki>{{Cleanup}}</nowiki> {{Cleanup}} </noinclude> a3bfa373be8d323884c14b53bca1a424acccbe90 294 292 2022-08-20T13:45:30Z Thalber 3 wikitext text/x-wiki <includeonly><div class="nomobile">{{Ambox | image = <p><span style="margin-right:15px>[[File:Hardhatcat.png|middle|47px]]</span> | type = '''Cleanup needed''' | info = This article needs structural or tonal clean-up to meet quality standards. Feel free to help {{fullurl|{{FULLPAGENAME}}|action=edit{{#if: {{{1|}}} | &section={{{1}}} }}|text=improve}} it.</p> | border = gray }}[[Category:Cleanup needed]]</div></includeonly> <noinclude> Usage: <nowiki>{{Cleanup}}</nowiki> {{Cleanup}} </noinclude> 566e408460cee47e34f3f5429469165e35c57a38 Template:todo 10 120 301 244 2022-08-20T14:06:47Z Thalber 3 trim wikitext text/x-wiki <includeonly><div class="nomobile">{{Ambox | image = <p><span style="margin-right:15px>[[File:monkPower.png|47px|middle]]</span> | type = '''This {{{target|section}}} is unfinished''' | info = This {{{target|section}}} is lacking some / all of critical information.</p> | border = gray }}</div>[[Category:Unfinished]]</includeonly><noinclude> Usage: <nowiki> {{todo}} {{todo|target=table}} (target defaults to "section") </nowiki> {{todo}} {{todo|target=table}} </noinclude> 0d6b542104747a7f451a3d6e499a69b18915f46c SlugBase 0 127 302 212 2022-08-20T14:06:55Z Thalber 3 wikitext text/x-wiki {{todo|target=article}} SlugBase is a framework created by SlimeCubed for adding additional slugcat characters to Rain World, with an emphasis on compatibility. It allows modders to tweak their character's common stats and colours, and is useful for as a base for new characters that have unique abilities (which can be achieved using [[BepInPlugins|hooking]]). SlugBase can be downloaded from [https://github.com/SlimeCubed/SlugBase/releases/latest here]. SlugBase's documentation can be found [https://github.com/SlimeCubed/SlugBase/wiki here]. [[Category:Code Mods]] [[Category:Dependencies]] ad23a88a14e53ea0a96ae61e5f24739b733d6686 Code Environments 0 126 303 228 2022-08-21T06:52:28Z Thalber 3 wikitext text/x-wiki This page contains is a guide on setting up a development environment for making code mods. == Reading Code == To mod Rain World, you need to be able to read the game's code. As it was written in C# and compiled against .NET Framework 3.5, you will need to use a decompiler to view the code. Remember that it is illegal to redistribute the game's code; decompiled copies are for your own use only. A few decompiler options are available to you, including: === dnSpy === [[File:dnspy.png|thumb|dnSpy being used to view the decompiled code of a mod's method in C#.]] '''Warning:''' in recent years, trojans have been released disguised as dnSpy, targetting security researchers. You should only download dnSpy from dnSpy's GitHub repository ([https://github.com/dnSpy/dnSpy/releases/latest dnSpy/dnSpy]). DnSpy is a .NET decompiler application that is designed to look visually similar to Visual Studio. It's popular with Rain World modders, modders of other .NET-based games, and security researchers. 32-bit and 64-bit Windows downloads can be found [https://github.com/dnSpy/dnSpy/releases/latest here]. dnSpy provides the most user convenience out of the options listed here, with handy usage analyzer and other inspection tools. It is, however, using an outdated version of decompiler backend, which causes it to choke and output invalid code in some cases (most notably, switch statements over strings). === ILSpy === ILSpy is a .NET decompiler backend. There are many frontends, often in the form of extensions for Visual Studio and Visual Studio Code. There's also a frontend built into JetBrains Rider. === ICsharpCode.Decompiler === Starting with version 2022, Visual Studio comes with its own decompiler: you can inspect classes from your reference libraries. == Writing Code == Most Rain World code modders use Visual Studio to write their code. This section will go over how to set up Visual Studio for Rain World modding. However, Visual Studio is limited to Windows, so you may find that Linux- and Mac-compatible options like [https://www.jetbrains.com/rider/ JetBrains Rider] and [https://code.visualstudio.com/ Visual Studio Code] are better suited to your use-case. === Installing Visual Studio === # Download the ''installer'' for latest version of VS [https://visualstudio.microsoft.com/downloads/ here]. Run it. # From the installer, create a new install of VS. In workload selection menu, make sure you have ".NET desktop development" selected. In Individual components, search for ".NET Framework 3.5 targeting pack" and enable it too. # Start the installation, wait for it to finish. [[File:CodeEnv-VSInstaller.png|none|thumb|alt=Visual Studio installer screen|Visual Studio installer screen]] === Creating a Visual Studio project === When creating a project for a rain world mod, you will need to a '''class library''' targeting '''.NET Framework 3.5'''. There are some problems you may encounter on this step. * Occasionally Visual Studio refuses to display targeting Framework 3.5 as an option. The pattern is unclear. * Creating a project targeting fw3.5 from Visual Studio's GUI causes it to be made with old <code>.csproj</code> file format (msbuild 2003), which restricts some features and is generally more messy. '''Steps to tell if the project is in older format''': ** Open the file in a text editor ** If it looks like a pile of piss-soaked spaghetti and has <code>Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"</code> around the beginning, it's old. Thus it's recommended to create project files from the command line with <code>dotnet new</code>: [[File:CodeEnv-DotnetCLI.png|none|thumb|alt=Creating a project with dotnet CLI|Creating a project with dotnet CLI]] Then open the resulting .csproj in Visual Studio, double click the project name in solution structure, and change the first block to have tags with following values: {| class="wikitable" |- ! Tag !! Value |- | TargetFramework || net35 |- | ImplicitUsings || disable |- | Nullable || disable |- | LangVersion || latest |} === Adding references === To compile mods and access the game code, you need to add some assemblies to your project as ''references''. To do this, you can * Use <code>Project -> Add project reference...</code> in VS. * Manually add <code>Include</code>s to your .csproj. For all mods, it is a good idea to reference: {|class="wikitable" |- ! Assembly !! Contains !! Notes |- | RainWorld_Data/Managed/AssemblyCSharp.dll || All of the vanilla game code || Use [https://github.com/Reinms/Stubber-Publicizer this tool] to remove accessibility restrictions |- | RainWorld_Data/Managed/UnityEngine.dll || Unity API methods |- | BepInEx/core/BepInEx.dll || [[BepInEx]] api |- | BepInEx/plugins/PartialityWrapper/HOOKS-Assembly-CSharp.dll || Hookgen events for methods in Assembly-CSharp for easily attaching code |- | BepInEx/core/MonoMod.RuntimeDetour || Classes and methods necessary for applying manual detours/hooks |- | BepInEx/core/MonoMod.Utils.dll || Classes and methods necessary for applying IL hooks, as well as some additional functionality |} Additionally, if you want to use a dependency mod, you will likely need to reference it too. If you are planning to share your code at some point, it is recommended that you set up your references without using absolute paths on your PC. This can be done in few ways: * Copying the reference files to a folder inside or near the project folder. * Setting up a folder symlink from somewhere in the project to a reference dir. On Windows, you can use [https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink mklink /J] from command prompt. In either case, you should [https://git-scm.com/docs/gitignore gitignore] references if they happen to be in a repo to avoid redistributing others' code. === Building === After you've wrote something, you will naturally want to run it and see if it works. As of now, there is no way of attaching a debugger to Rain World process, and version of Mono packed with the game does not load .pdb files. Thus you should always build your mods on Release configuration, even if you're mid-development. To load a mod into the game, you need to copy its assembly into respective BepInEx active folder (<code>BepInEx/plugins/</code> unless you are making an [[MonoMod Patches|mmpatch]]). You can automate this step by using a build event: * In Project properties view in VS, find Build Events, and into Post-build insert one of these: ** Unconditional build event with hardcoded destination: <code>copy /Y "$(TargetPath)" "Path/to/your/plugins/folder/here"</code> ** Copies files into a path defined by environment variable <code>RWMods</code> (if it exists): <code>if defined RWMods (copy /Y "$(TargetPath)" "%RWMods%")</code> By default, building a project copies most of its dependencies to the build destination (<code>bin/release/</code>). You can prevent it by selecting desired references in solution explorer, opening properties dock and setting <code>Copy Local</code> to <code>No</code>: [[File:CodeEnv-copyLocal.png|thumb|none|alt=Disabling Copy Local|Disabling Copy Local]] === Testing and Debugging === {{todo}} As mentioned, attaching a debugger to the game is currently not an option. This sections will contain several tips on mitigating the pain. * You can enable a separate console window for BepInEx output in <code>BepInEx/config/bepinex.cfg</code>. * From a [[BepInPlugins|BepInEx plugin]], use <code>Logger</code> property. If you need to lend access to your logger to different class, use something like: <syntaxhighlight lang="csharp"> public class MyPlugin : Baseunityplugin { public MyPlugin() { __me = new(this); } //using WeakReference to allow garbage collection private static WeakReference __me; public static MyPlugin ME => __me?.target as MyPlugin; //wrapper property. If you don't need a static member, just do this and pass plugin instance around. public ManualLogSource Logger_p => Logger; } //... MyPlugin.ME.Logger_p.Log(); </syntaxhighlight> * [https://github.com/casheww/RW-ToolBox/releases/latest This plugin] by casheww might help you with specific tasks == Misc tips and trivia == {{todo}} * You can use Embedded Resources to include arbitrary data, such as text files or images, with your assembly. To do this, select a file in Solution explorer, open Properties dock, and set <code>Build action</code> to <code>Embedded Resource</code>. You can retrieve the resources as <code>byte[]</code>s using methods '''GetManifestResourceNames''' and '''GetManifestResourceStream''' on <code>System.Reflection.Assembly</code> instance. [[Category:Code Mods]] 3bc096b7e3f8bd992410502d746505657902a2eb 304 303 2022-08-21T09:11:58Z Thalber 3 /* Writing Code */ add non-VS wikitext text/x-wiki This page contains is a guide on setting up a development environment for making code mods. == Reading Code == To mod Rain World, you need to be able to read the game's code. As it was written in C# and compiled against .NET Framework 3.5, you will need to use a decompiler to view the code. Remember that it is illegal to redistribute the game's code; decompiled copies are for your own use only. A few decompiler options are available to you, including: === dnSpy === [[File:dnspy.png|thumb|dnSpy being used to view the decompiled code of a mod's method in C#.]] '''Warning:''' in recent years, trojans have been released disguised as dnSpy, targetting security researchers. You should only download dnSpy from dnSpy's GitHub repository ([https://github.com/dnSpy/dnSpy/releases/latest dnSpy/dnSpy]). DnSpy is a .NET decompiler application that is designed to look visually similar to Visual Studio. It's popular with Rain World modders, modders of other .NET-based games, and security researchers. 32-bit and 64-bit Windows downloads can be found [https://github.com/dnSpy/dnSpy/releases/latest here]. dnSpy provides the most user convenience out of the options listed here, with handy usage analyzer and other inspection tools. It is, however, using an outdated version of decompiler backend, which causes it to choke and output invalid code in some cases (most notably, switch statements over strings). === ILSpy === ILSpy is a .NET decompiler backend. There are many frontends, often in the form of extensions for Visual Studio and Visual Studio Code. There's also a frontend built into JetBrains Rider. === ICsharpCode.Decompiler === Starting with version 2022, Visual Studio comes with its own decompiler: you can inspect classes from your reference libraries. == Writing Code == Most Rain World code modders use Visual Studio to write their code. This section will go over that, as well as a more generalized lightweight option. Please note that Visual Studio is not the only IDE out there: for example, [https://www.jetbrains.com/rider/ JetBrains Rider] is a good cross-platform choice if you have the money for it. <div class="wikitable"> <tabber> |-| Visual Studio= Visual Studio is one of the best development environments for C# and .NET in general. It comes with many useful tools, such as autocompletion AI, builtin syntax highlighting, built-in decompiler and graphical interfaces for configuring .NET projects. However, it also has several disadvantages: * '''Disk space issue''': every installation of Visual Studio occupies at least 5-6 GB on your drive, possibly more. * '''Portability''': VS is Windows-only. * '''Editor performance''': VS becomes less responsive on old machines. === Installing Visual Studio === # Download the ''installer'' for latest version of VS [https://visualstudio.microsoft.com/downloads/ here]. Run it. # From the installer, create a new install of VS. In workload selection menu, make sure you have ".NET desktop development" selected. In Individual components, search for ".NET Framework 3.5 targeting pack" and enable it too. # Start the installation, wait for it to finish. [[File:CodeEnv-VSInstaller.png|none|thumb|alt=Visual Studio installer screen|Visual Studio installer screen]] === Creating a project === When creating a project for a rain world mod, you will need to a '''class library''' targeting '''.NET Framework 3.5'''. There are some problems you may encounter on this step. * Occasionally Visual Studio refuses to display targeting Framework 3.5 as an option. The pattern is unclear. * Creating a project targeting fw3.5 from Visual Studio's GUI causes it to be made with old <code>.csproj</code> file format (msbuild 2003), which restricts some features and is generally more messy. '''Steps to tell if the project is in older format''': ** Open the file in a text editor ** If it looks like a pile of piss-soaked spaghetti and has <code>Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"</code> around the beginning, it's old. Thus it's recommended to create project files from the command line with <code>dotnet new</code>: [[File:CodeEnv-DotnetCLI.png|none|thumb|alt=Creating a project with dotnet CLI|Creating a project with dotnet CLI]] Then open the resulting .csproj in Visual Studio, double click the project name in solution structure, and change the first block to have tags with following values: === Adding references === To compile mods and access the game code, you need to add some assemblies to your project as ''references''. To do this, you can * Use <code>Project -> Add project reference...</code> in VS. * Manually add <code>Include</code>s to your .csproj. List of common required references is in the section [[#Common references]]. If you are planning to share your code at some point, it is recommended that you set up your references without using absolute paths on your PC. This can be done in few ways: * Copying the reference files to a folder inside or near the project folder. * Setting up a folder symlink from somewhere in the project to a reference dir. On Windows, you can use [https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink mklink /J] from command prompt. In either case, you should [https://git-scm.com/docs/gitignore gitignore] references if they happen to be in a repo to avoid redistributing others' code. === Building === After you've wrote something, you will naturally want to run it and see if it works. As of now, there is no way of attaching a debugger to Rain World process, and version of Mono packed with the game does not load .pdb files. Thus you should always build your mods on Release configuration, even if you're mid-development. To load a mod into the game, you need to copy its assembly into respective BepInEx active folder (<code>BepInEx/plugins/</code> unless you are making an [[MonoMod Patches|mmpatch]]). You can automate this step by using a build event: * In Project properties view in VS, find Build Events, and into Post-build insert one of these: ** Unconditional build event with hardcoded destination: <code>copy /Y "$(TargetPath)" "Path/to/your/plugins/folder/here"</code> ** Copies files into a path defined by environment variable <code>RWMods</code> (if it exists): <code>if defined RWMods (copy /Y "$(TargetPath)" "%RWMods%")</code> By default, building a project copies most of its dependencies to the build destination (<code>bin/release/</code>). You can prevent it by selecting desired references in solution explorer, opening properties dock and setting <code>Copy Local</code> to <code>No</code>: [[File:CodeEnv-copyLocal.png|thumb|none|alt=Disabling Copy Local|Disabling Copy Local]] |-| Simple code editor + dotnet CLI= {{todo|target=tab}} Another option is using a simpler code editor (such as [https://code.visualstudio.com/ Visual Studio Code] with a c# extension, or even [https://notepad-plus-plus.org/downloads/ notepad++] if you enjoy torture). This setup lacks advanced functions of Visual Studio, but allows you to write and build on non-windows systems. === Installing .NET SDK === Download the latest .NET SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/6.0 6.0.400]) and install it. New SDKs are able to build projects for old runtimes. Use the SDK via <code>dotnet</code> from the command line. Full docs for the command can be found [https://docs.microsoft.com/en-us/dotnet/core/tools/ here]. === Creating a project === Use <code>dotnet new classlib -n [projectName]</code> to create a project. After it's there, open the .csproj file and edit the first <code>PropertyGroup</code> according to [[#csproj PropertyGroup]] section. After this is done, you can start writing. Any '''.cs''' file put into the project folder or one of its subfolders is automatically included. === Adding references === You can add a reference to the project by including <pre><nowiki> <Reference Include="path/to/Assembly.dll"> </Reference> </nowiki></pre> in an <code>ItemGroup</code>. Wildcards and relative paths are supported. To disable copying of references to target directory, change the include tag to look like the following: <pre><nowiki> <Reference Include="libs/*.dll"> <Private>false</Private> </Reference> </nowiki></pre> === Building === Use <code>dotnet build</code> in your project directory to build your project. Output goes into <code>bin/[Debug//Release]/</code> depending on your current configuration. </tabber> </div> ==== Common references ==== For all mods, it is a good idea to reference: {|class="wikitable" |- ! Assembly !! Contains !! Notes |- | RainWorld_Data/Managed/AssemblyCSharp.dll || All of the vanilla game code || Use [https://github.com/Reinms/Stubber-Publicizer this tool] to remove accessibility restrictions |- | RainWorld_Data/Managed/UnityEngine.dll || Unity API methods |- | BepInEx/core/BepInEx.dll || [[BepInEx]] api |- | BepInEx/plugins/PartialityWrapper/HOOKS-Assembly-CSharp.dll || Hookgen events for methods in Assembly-CSharp for easily attaching code |- | BepInEx/core/MonoMod.RuntimeDetour || Classes and methods necessary for applying manual detours/hooks |- | BepInEx/core/MonoMod.Utils.dll || Classes and methods necessary for applying IL hooks, as well as some additional functionality |} Additionally, if you want to use a dependency mod, you will likely need to reference it too. ==== csproj PropertyGroup ==== When creating a csproj file from CLI, you will need to edit it to have following values: {| class="wikitable" |- ! Tag !! Value !! Comment |- | TargetFramework || net35 || Framework version |- | ImplicitUsings || disable || Can not be used on .NET Framework 3.5 |- | Nullable || disable || Toggles some compile-time null checking rules.<br />You can keep it enabled,<br />but it won't apply to the game code. |- | LangVersion || latest || Without this tag, language version stays at C#7.3<br />Later language versions include some handy features. |} ==== csproj structure ==== {{todo}} [[File:CodeEnv-csprojStructure.png|thumb|none|alt=Visual example|Visual example]] Official reference for .NET SDK .csproj format can be found [https://docs.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props here]. === Testing and Debugging === {{todo}} As mentioned, attaching a debugger to the game is currently not an option. This sections will contain several tips on mitigating the pain. * You can enable a separate console window for BepInEx output in <code>BepInEx/config/bepinex.cfg</code>. * From a [[BepInPlugins|BepInEx plugin]], use <code>Logger</code> property. If you need to lend access to your logger to different class, use something like: <syntaxhighlight lang="csharp"> public class MyPlugin : Baseunityplugin { public MyPlugin() { __me = new(this); } //using WeakReference to allow garbage collection private static WeakReference __me; public static MyPlugin ME => __me?.target as MyPlugin; //wrapper property. If you don't need a static member, just do this and pass plugin instance around. public ManualLogSource Logger_p => Logger; } //... MyPlugin.ME.Logger_p.Log(); </syntaxhighlight> * [https://github.com/casheww/RW-ToolBox/releases/latest This plugin] by casheww might help you with specific tasks == Misc tips and trivia == {{todo}} * You can use Embedded Resources to include arbitrary data, such as text files or images, with your assembly. To do this, select a file in Solution explorer, open Properties dock, and set <code>Build action</code> to <code>Embedded Resource</code>. You can retrieve the resources as <code>byte[]</code>s using methods '''GetManifestResourceNames''' and '''GetManifestResourceStream''' on <code>System.Reflection.Assembly</code> instance. [[Category:Code Mods]] 120dad65c3da13e5bf0dd08733e5b08fa3311f81 362 304 2023-01-27T19:44:41Z Alextabitha 44 Updated .NET 3.5 to 4.8 wikitext text/x-wiki This page contains is a guide on setting up a development environment for making code mods. == Reading Code == To mod Rain World, you need to be able to read the game's code. As it was written in C# and compiled against .NET Framework 4.8, you will need to use a decompiler to view the code. Remember that it is illegal to redistribute the game's code; decompiled copies are for your own use only. A few decompiler options are available to you, including: === dnSpy === [[File:dnspy.png|thumb|dnSpy being used to view the decompiled code of a mod's method in C#.]] '''Warning:''' in recent years, trojans have been released disguised as dnSpy, targetting security researchers. You should only download dnSpy from dnSpy's GitHub repository ([https://github.com/dnSpy/dnSpy/releases/latest dnSpy/dnSpy]). DnSpy is a .NET decompiler application that is designed to look visually similar to Visual Studio. It's popular with Rain World modders, modders of other .NET-based games, and security researchers. 32-bit and 64-bit Windows downloads can be found [https://github.com/dnSpy/dnSpy/releases/latest here]. dnSpy provides the most user convenience out of the options listed here, with handy usage analyzer and other inspection tools. It is, however, using an outdated version of decompiler backend, which causes it to choke and output invalid code in some cases (most notably, switch statements over strings). === ILSpy === ILSpy is a .NET decompiler backend. There are many frontends, often in the form of extensions for Visual Studio and Visual Studio Code. There's also a frontend built into JetBrains Rider. === ICsharpCode.Decompiler === Starting with version 2022, Visual Studio comes with its own decompiler: you can inspect classes from your reference libraries. == Writing Code == Most Rain World code modders use Visual Studio to write their code. This section will go over that, as well as a more generalized lightweight option. Please note that Visual Studio is not the only IDE out there: for example, [https://www.jetbrains.com/rider/ JetBrains Rider] is a good cross-platform choice if you have the money for it. <div class="wikitable"> <tabber> |-| Visual Studio= Visual Studio is one of the best development environments for C# and .NET in general. It comes with many useful tools, such as autocompletion AI, builtin syntax highlighting, built-in decompiler and graphical interfaces for configuring .NET projects. However, it also has several disadvantages: * '''Disk space issue''': every installation of Visual Studio occupies at least 5-6 GB on your drive, possibly more. * '''Portability''': VS is Windows-only. * '''Editor performance''': VS becomes less responsive on old machines. === Installing Visual Studio === # Download the ''installer'' for latest version of VS [https://visualstudio.microsoft.com/downloads/ here]. Run it. # From the installer, create a new install of VS. In workload selection menu, make sure you have ".NET desktop development" selected. In Individual components, search for ".NET Framework 4.8 targeting pack" and enable it too. # Start the installation, wait for it to finish. [[File:CodeEnv-VSInstaller.png|none|thumb|alt=Visual Studio installer screen|Visual Studio installer screen]] === Creating a project === When creating a project for a rain world mod, you will need to a '''class library''' targeting '''.NET Framework 4.8'''. There are some problems you may encounter on this step. * Occasionally Visual Studio refuses to display targeting Framework 4.8 as an option. The pattern is unclear. * Creating a project targeting fw4.8 from Visual Studio's GUI causes it to be made with old <code>.csproj</code> file format (msbuild 2003), which restricts some features and is generally more messy. '''Steps to tell if the project is in older format''': ** Open the file in a text editor ** If it looks like a pile of piss-soaked spaghetti and has <code>Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"</code> around the beginning, it's old. Thus it's recommended to create project files from the command line with <code>dotnet new</code>: [[File:CodeEnv-DotnetCLI.png|none|thumb|alt=Creating a project with dotnet CLI|Creating a project with dotnet CLI]] Then open the resulting .csproj in Visual Studio, double click the project name in solution structure, and change the first block to have tags with following values: === Adding references === To compile mods and access the game code, you need to add some assemblies to your project as ''references''. To do this, you can * Use <code>Project -> Add project reference...</code> in VS. * Manually add <code>Include</code>s to your .csproj. List of common required references is in the section [[#Common references]]. If you are planning to share your code at some point, it is recommended that you set up your references without using absolute paths on your PC. This can be done in few ways: * Copying the reference files to a folder inside or near the project folder. * Setting up a folder symlink from somewhere in the project to a reference dir. On Windows, you can use [https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink mklink /J] from command prompt. In either case, you should [https://git-scm.com/docs/gitignore gitignore] references if they happen to be in a repo to avoid redistributing others' code. === Building === After you've wrote something, you will naturally want to run it and see if it works. As of now, there is no way of attaching a debugger to Rain World process, and version of Mono packed with the game does not load .pdb files. Thus you should always build your mods on Release configuration, even if you're mid-development. To load a mod into the game, you need to copy its assembly into respective BepInEx active folder (<code>BepInEx/plugins/</code> unless you are making an [[MonoMod Patches|mmpatch]]). You can automate this step by using a build event: * In Project properties view in VS, find Build Events, and into Post-build insert one of these: ** Unconditional build event with hardcoded destination: <code>copy /Y "$(TargetPath)" "Path/to/your/plugins/folder/here"</code> ** Copies files into a path defined by environment variable <code>RWMods</code> (if it exists): <code>if defined RWMods (copy /Y "$(TargetPath)" "%RWMods%")</code> By default, building a project copies most of its dependencies to the build destination (<code>bin/release/</code>). You can prevent it by selecting desired references in solution explorer, opening properties dock and setting <code>Copy Local</code> to <code>No</code>: [[File:CodeEnv-copyLocal.png|thumb|none|alt=Disabling Copy Local|Disabling Copy Local]] |-| Simple code editor + dotnet CLI= {{todo|target=tab}} Another option is using a simpler code editor (such as [https://code.visualstudio.com/ Visual Studio Code] with a c# extension, or even [https://notepad-plus-plus.org/downloads/ notepad++] if you enjoy torture). This setup lacks advanced functions of Visual Studio, but allows you to write and build on non-windows systems. === Installing .NET SDK === Download the latest .NET SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/6.0 6.0.400]) and install it. New SDKs are able to build projects for old runtimes. Use the SDK via <code>dotnet</code> from the command line. Full docs for the command can be found [https://docs.microsoft.com/en-us/dotnet/core/tools/ here]. === Creating a project === Use <code>dotnet new classlib -n [projectName]</code> to create a project. After it's there, open the .csproj file and edit the first <code>PropertyGroup</code> according to [[#csproj PropertyGroup]] section. After this is done, you can start writing. Any '''.cs''' file put into the project folder or one of its subfolders is automatically included. === Adding references === You can add a reference to the project by including <pre><nowiki> <Reference Include="path/to/Assembly.dll"> </Reference> </nowiki></pre> in an <code>ItemGroup</code>. Wildcards and relative paths are supported. To disable copying of references to target directory, change the include tag to look like the following: <pre><nowiki> <Reference Include="libs/*.dll"> <Private>false</Private> </Reference> </nowiki></pre> === Building === Use <code>dotnet build</code> in your project directory to build your project. Output goes into <code>bin/[Debug//Release]/</code> depending on your current configuration. </tabber> </div> ==== Common references ==== For all mods, it is a good idea to reference: {|class="wikitable" |- ! Assembly !! Contains !! Notes |- | RainWorld_Data/Managed/AssemblyCSharp.dll || All of the vanilla game code || Use [https://github.com/Reinms/Stubber-Publicizer this tool] to remove accessibility restrictions |- | RainWorld_Data/Managed/UnityEngine.dll || Unity API methods |- | BepInEx/core/BepInEx.dll || [[BepInEx]] api |- | BepInEx/plugins/PartialityWrapper/HOOKS-Assembly-CSharp.dll || Hookgen events for methods in Assembly-CSharp for easily attaching code |- | BepInEx/core/MonoMod.RuntimeDetour || Classes and methods necessary for applying manual detours/hooks |- | BepInEx/core/MonoMod.Utils.dll || Classes and methods necessary for applying IL hooks, as well as some additional functionality |} Additionally, if you want to use a dependency mod, you will likely need to reference it too. ==== csproj PropertyGroup ==== When creating a csproj file from CLI, you will need to edit it to have following values: {| class="wikitable" |- ! Tag !! Value !! Comment |- | TargetFramework || net48 || Framework version |- | ImplicitUsings || disable || Can not be used on .NET Framework 4.8 only 6+ |- | Nullable || disable || Toggles some compile-time null checking rules.<br />You can keep it enabled,<br />but it won't apply to the game code. |- | LangVersion || latest || Without this tag, language version stays at C#7.3<br />Later language versions include some handy features. |} ==== csproj structure ==== {{todo}} [[File:CodeEnv-csprojStructure.png|thumb|none|alt=Visual example|Visual example]] Official reference for .NET SDK .csproj format can be found [https://docs.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props here]. === Testing and Debugging === {{todo}} As mentioned, attaching a debugger to the game is currently not an option. This sections will contain several tips on mitigating the pain. * You can enable a separate console window for BepInEx output in <code>BepInEx/config/bepinex.cfg</code>. * From a [[BepInPlugins|BepInEx plugin]], use <code>Logger</code> property. If you need to lend access to your logger to different class, use something like: <syntaxhighlight lang="csharp"> public class MyPlugin : Baseunityplugin { public MyPlugin() { __me = new(this); } //using WeakReference to allow garbage collection private static WeakReference __me; public static MyPlugin ME => __me?.target as MyPlugin; //wrapper property. If you don't need a static member, just do this and pass plugin instance around. public ManualLogSource Logger_p => Logger; } //... MyPlugin.ME.Logger_p.Log(); </syntaxhighlight> * [https://github.com/casheww/RW-ToolBox/releases/latest This plugin] by casheww might help you with specific tasks == Misc tips and trivia == {{todo}} * You can use Embedded Resources to include arbitrary data, such as text files or images, with your assembly. To do this, select a file in Solution explorer, open Properties dock, and set <code>Build action</code> to <code>Embedded Resource</code>. You can retrieve the resources as <code>byte[]</code>s using methods '''GetManifestResourceNames''' and '''GetManifestResourceStream''' on <code>System.Reflection.Assembly</code> instance. [[Category:Code Mods]] 3684e176d77a912f5ccfa93d2c796701b48a5d00 363 362 2023-01-27T19:47:47Z Alextabitha 44 Updated filepath wikitext text/x-wiki This page contains is a guide on setting up a development environment for making code mods. == Reading Code == To mod Rain World, you need to be able to read the game's code. As it was written in C# and compiled against .NET Framework 4.8, you will need to use a decompiler to view the code. Remember that it is illegal to redistribute the game's code; decompiled copies are for your own use only. A few decompiler options are available to you, including: === dnSpy === [[File:dnspy.png|thumb|dnSpy being used to view the decompiled code of a mod's method in C#.]] '''Warning:''' in recent years, trojans have been released disguised as dnSpy, targetting security researchers. You should only download dnSpy from dnSpy's GitHub repository ([https://github.com/dnSpy/dnSpy/releases/latest dnSpy/dnSpy]). DnSpy is a .NET decompiler application that is designed to look visually similar to Visual Studio. It's popular with Rain World modders, modders of other .NET-based games, and security researchers. 32-bit and 64-bit Windows downloads can be found [https://github.com/dnSpy/dnSpy/releases/latest here]. dnSpy provides the most user convenience out of the options listed here, with handy usage analyzer and other inspection tools. It is, however, using an outdated version of decompiler backend, which causes it to choke and output invalid code in some cases (most notably, switch statements over strings). === ILSpy === ILSpy is a .NET decompiler backend. There are many frontends, often in the form of extensions for Visual Studio and Visual Studio Code. There's also a frontend built into JetBrains Rider. === ICsharpCode.Decompiler === Starting with version 2022, Visual Studio comes with its own decompiler: you can inspect classes from your reference libraries. == Writing Code == Most Rain World code modders use Visual Studio to write their code. This section will go over that, as well as a more generalized lightweight option. Please note that Visual Studio is not the only IDE out there: for example, [https://www.jetbrains.com/rider/ JetBrains Rider] is a good cross-platform choice if you have the money for it. <div class="wikitable"> <tabber> |-| Visual Studio= Visual Studio is one of the best development environments for C# and .NET in general. It comes with many useful tools, such as autocompletion AI, builtin syntax highlighting, built-in decompiler and graphical interfaces for configuring .NET projects. However, it also has several disadvantages: * '''Disk space issue''': every installation of Visual Studio occupies at least 5-6 GB on your drive, possibly more. * '''Portability''': VS is Windows-only. * '''Editor performance''': VS becomes less responsive on old machines. === Installing Visual Studio === # Download the ''installer'' for latest version of VS [https://visualstudio.microsoft.com/downloads/ here]. Run it. # From the installer, create a new install of VS. In workload selection menu, make sure you have ".NET desktop development" selected. In Individual components, search for ".NET Framework 4.8 targeting pack" and enable it too. # Start the installation, wait for it to finish. [[File:CodeEnv-VSInstaller.png|none|thumb|alt=Visual Studio installer screen|Visual Studio installer screen]] === Creating a project === When creating a project for a rain world mod, you will need to a '''class library''' targeting '''.NET Framework 4.8'''. There are some problems you may encounter on this step. * Occasionally Visual Studio refuses to display targeting Framework 4.8 as an option. The pattern is unclear. * Creating a project targeting fw4.8 from Visual Studio's GUI causes it to be made with old <code>.csproj</code> file format (msbuild 2003), which restricts some features and is generally more messy. '''Steps to tell if the project is in older format''': ** Open the file in a text editor ** If it looks like a pile of piss-soaked spaghetti and has <code>Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"</code> around the beginning, it's old. Thus it's recommended to create project files from the command line with <code>dotnet new</code>: [[File:CodeEnv-DotnetCLI.png|none|thumb|alt=Creating a project with dotnet CLI|Creating a project with dotnet CLI]] Then open the resulting .csproj in Visual Studio, double click the project name in solution structure, and change the first block to have tags with following values: === Adding references === To compile mods and access the game code, you need to add some assemblies to your project as ''references''. To do this, you can * Use <code>Project -> Add project reference...</code> in VS. * Manually add <code>Include</code>s to your .csproj. List of common required references is in the section [[#Common references]]. If you are planning to share your code at some point, it is recommended that you set up your references without using absolute paths on your PC. This can be done in few ways: * Copying the reference files to a folder inside or near the project folder. * Setting up a folder symlink from somewhere in the project to a reference dir. On Windows, you can use [https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink mklink /J] from command prompt. In either case, you should [https://git-scm.com/docs/gitignore gitignore] references if they happen to be in a repo to avoid redistributing others' code. === Building === After you've wrote something, you will naturally want to run it and see if it works. As of now, there is no way of attaching a debugger to Rain World process, and version of Mono packed with the game does not load .pdb files. Thus you should always build your mods on Release configuration, even if you're mid-development. To load a mod into the game, you need to copy its assembly into respective BepInEx active folder (<code>BepInEx/plugins/</code> unless you are making an [[MonoMod Patches|mmpatch]]). You can automate this step by using a build event: * In Project properties view in VS, find Build Events, and into Post-build insert one of these: ** Unconditional build event with hardcoded destination: <code>copy /Y "$(TargetPath)" "Path/to/your/plugins/folder/here"</code> ** Copies files into a path defined by environment variable <code>RWMods</code> (if it exists): <code>if defined RWMods (copy /Y "$(TargetPath)" "%RWMods%")</code> By default, building a project copies most of its dependencies to the build destination (<code>bin/release/</code>). You can prevent it by selecting desired references in solution explorer, opening properties dock and setting <code>Copy Local</code> to <code>No</code>: [[File:CodeEnv-copyLocal.png|thumb|none|alt=Disabling Copy Local|Disabling Copy Local]] |-| Simple code editor + dotnet CLI= {{todo|target=tab}} Another option is using a simpler code editor (such as [https://code.visualstudio.com/ Visual Studio Code] with a c# extension, or even [https://notepad-plus-plus.org/downloads/ notepad++] if you enjoy torture). This setup lacks advanced functions of Visual Studio, but allows you to write and build on non-windows systems. === Installing .NET SDK === Download the latest .NET SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/6.0 6.0.400]) and install it. New SDKs are able to build projects for old runtimes. Use the SDK via <code>dotnet</code> from the command line. Full docs for the command can be found [https://docs.microsoft.com/en-us/dotnet/core/tools/ here]. === Creating a project === Use <code>dotnet new classlib -n [projectName]</code> to create a project. After it's there, open the .csproj file and edit the first <code>PropertyGroup</code> according to [[#csproj PropertyGroup]] section. After this is done, you can start writing. Any '''.cs''' file put into the project folder or one of its subfolders is automatically included. === Adding references === You can add a reference to the project by including <pre><nowiki> <Reference Include="path/to/Assembly.dll"> </Reference> </nowiki></pre> in an <code>ItemGroup</code>. Wildcards and relative paths are supported. To disable copying of references to target directory, change the include tag to look like the following: <pre><nowiki> <Reference Include="libs/*.dll"> <Private>false</Private> </Reference> </nowiki></pre> === Building === Use <code>dotnet build</code> in your project directory to build your project. Output goes into <code>bin/[Debug//Release]/</code> depending on your current configuration. </tabber> </div> ==== Common references ==== For all mods, it is a good idea to reference: {|class="wikitable" |- ! Assembly !! Contains !! Notes |- | RainWorld_Data/Managed/AssemblyCSharp.dll || All of the vanilla game code || Use [https://github.com/Reinms/Stubber-Publicizer this tool] to remove accessibility restrictions |- | RainWorld_Data/Managed/UnityEngine.dll || Unity API methods |- | BepInEx/core/BepInEx.dll || [[BepInEx]] api |- | BepInEx/plugins/HOOKS-Assembly-CSharp.dll || Hookgen events for methods in Assembly-CSharp for easily attaching code |- | BepInEx/core/MonoMod.RuntimeDetour || Classes and methods necessary for applying manual detours/hooks |- | BepInEx/core/MonoMod.Utils.dll || Classes and methods necessary for applying IL hooks, as well as some additional functionality |} Additionally, if you want to use a dependency mod, you will likely need to reference it too. ==== csproj PropertyGroup ==== When creating a csproj file from CLI, you will need to edit it to have following values: {| class="wikitable" |- ! Tag !! Value !! Comment |- | TargetFramework || net48 || Framework version |- | ImplicitUsings || disable || Can not be used on .NET Framework 4.8 only 6+ |- | Nullable || disable || Toggles some compile-time null checking rules.<br />You can keep it enabled,<br />but it won't apply to the game code. |- | LangVersion || latest || Without this tag, language version stays at C#7.3<br />Later language versions include some handy features. |} ==== csproj structure ==== {{todo}} [[File:CodeEnv-csprojStructure.png|thumb|none|alt=Visual example|Visual example]] Official reference for .NET SDK .csproj format can be found [https://docs.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props here]. === Testing and Debugging === {{todo}} As mentioned, attaching a debugger to the game is currently not an option. This sections will contain several tips on mitigating the pain. * You can enable a separate console window for BepInEx output in <code>BepInEx/config/bepinex.cfg</code>. * From a [[BepInPlugins|BepInEx plugin]], use <code>Logger</code> property. If you need to lend access to your logger to different class, use something like: <syntaxhighlight lang="csharp"> public class MyPlugin : Baseunityplugin { public MyPlugin() { __me = new(this); } //using WeakReference to allow garbage collection private static WeakReference __me; public static MyPlugin ME => __me?.target as MyPlugin; //wrapper property. If you don't need a static member, just do this and pass plugin instance around. public ManualLogSource Logger_p => Logger; } //... MyPlugin.ME.Logger_p.Log(); </syntaxhighlight> * [https://github.com/casheww/RW-ToolBox/releases/latest This plugin] by casheww might help you with specific tasks == Misc tips and trivia == {{todo}} * You can use Embedded Resources to include arbitrary data, such as text files or images, with your assembly. To do this, select a file in Solution explorer, open Properties dock, and set <code>Build action</code> to <code>Embedded Resource</code>. You can retrieve the resources as <code>byte[]</code>s using methods '''GetManifestResourceNames''' and '''GetManifestResourceStream''' on <code>System.Reflection.Assembly</code> instance. [[Category:Code Mods]] f19b615433d782c8d887bec3ee4e6dbb67e068c2 Template:Cn 10 153 305 2022-08-21T09:38:33Z Thalber 3 Created page with "<includeonly>[[Category:Verification_Needed]]<small><sup>[[:Category:Verification_Needed|[{{{1|verify!}}}]]]</sup></small></includeonly><noinclude> Denotes a statement for future validity check. == Usage == <code><nowiki>Every dog has 6 legs{{Cn}}</nowiki></code> Every dog has 6 legs{{Cn}} <code><nowiki>Every dog has 6 legs{{Cn|what?}}</nowiki></code> Every dog has 6 legs{{Cn|what?}} </noinclude>" wikitext text/x-wiki <includeonly>[[Category:Verification_Needed]]<small><sup>[[:Category:Verification_Needed|[{{{1|verify!}}}]]]</sup></small></includeonly><noinclude> Denotes a statement for future validity check. == Usage == <code><nowiki>Every dog has 6 legs{{Cn}}</nowiki></code> Every dog has 6 legs{{Cn}} <code><nowiki>Every dog has 6 legs{{Cn|what?}}</nowiki></code> Every dog has 6 legs{{Cn|what?}} </noinclude> f88ee3d3a7516c5cfd26c896e35eab22ca82e99b 306 305 2022-08-21T09:39:27Z Thalber 3 wikitext text/x-wiki <includeonly>[[Category:Verification_Needed]]<small><sup>[[:Category:Verification_Needed|[Cn:{{{1|verify!}}}]]]</sup></small></includeonly><noinclude> Denotes a statement for future validity check. == Usage == <code><nowiki>Every dog has 6 legs{{Cn}}</nowiki></code> Every dog has 6 legs{{Cn}} <code><nowiki>Every dog has 6 legs{{Cn|what?}}</nowiki></code> Every dog has 6 legs{{Cn|what?}} </noinclude> 2187f5bd40e3bcf332c9979b76794d335d232cdd Category:Verification Needed 14 154 307 2022-08-21T09:39:56Z Thalber 3 Created page with "This category contains pages with unverified information." wikitext text/x-wiki This category contains pages with unverified information. 630aff6ab9263e6f8b33d36a1125f718931cb3ed Downpour Reference 0 144 308 280 2022-08-21T19:36:09Z AndrewFM 14 wikitext text/x-wiki '''Remix''' is a modloader to be included with the game starting with release of Downpour. It is based on [[BepInEx]], and features an in-game mod management menu much like [[Realm]]. This section contains descriptions of both Remix usage and notable changes to incoming vanilla architecture. == Technical reference == * [[/Mod_Directories]] - Mod folder structure * [[/File_Formats]] - Changes in game file formats * [[/Modification_Files]] - Asset-driven file merging * [[/BepInEx_Files]] - handling of mods' .dll files * [[/ExtEnum]] - built-in replacement for [[EnumExtender]] * [[/Conflict_Merging]] - automatic conflict resolution 653cb41219c1ba3fc627795d03d75b15f67300cb Dev Tools 0 84 314 288 2022-08-27T18:53:15Z Tronsx 19 wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ==Interface Tabs== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. <div class="wikitable"><tabber> |-| Room settings= This tab mostly contains settings for base room visuals, such as palette, cloud cover and terrain wetness. === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === [[File:Fadepalette example.png]] ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image on the right shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! {|class="wikitable" |- ! '''Effect''' !! '''Description''' !! '''Showcase''' |- | SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. || [[File:Effect 1.png|frameless|The effect at 100%]] |- | SkyBloom || Increases how fuzzy/bloomy the sky's light is. |- | LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. |- | Bloom || Similar to SkyBloom, but applies to lights. |- | Fog || Creates a white cloudy effect at layer 1. Not compatible with |- | Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- |- | GreenSparks || Underhang, and the Legs' green sparkles. |- | VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | Flies || Spawns small flys that buzz around the room and land on objects. |- | FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | TinyDragonFly || Spawns tiny bugs that fly around plants. |- | RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | Ant || Spawns small jumping bugs. |- | Beetle || Spawns small beetles that slowly fly around the room. |- | WaterGlowWorm || Spawns small worms that swim around in water. |- | Wasp || Spawns small wasps that quickly dart between walls. |- | Moth || Spawns small white moths which slowly flutter around the room. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom`, VoidMelt </syntaxhighlight> |-| Objects= Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds= [[File:soundTab.png|400px|right|border|]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map= {{todo|target=tab}} [[File:mapTab.png|400px|right|border|]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections.png|400px|right|border|Connections on dev map]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png|400px|right|border|Canon view of the map]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png|400px|right|border|Example of a rendered map .png file]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers= {{todo|target=tab}} [[File:triggerTab.png|600px|right|border|Trigger tab view]] <span id="general-controls"></span> == General controls == === Save === Saves the current effects and room settings to a file inside the region’s World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by pressing R and returning to the room to see the changes. === Inherent from template === Will set the values stored in a specific template the region has to this room. === Save as template: === Saves the current room’s settings as a template for easy re-use. == Triggers Menu == '''Triggers''' are the mechanism in which some in-game events occur, such as specific songs playing, projections being displayed by the player guide overseer, or information text being displayed at the bottom of the screen. Clicking one of the four options in the bottom right-hand box will place a trigger of that type, which can be moved just like other devtools objects. === Trigger Options === Triggers have a number of settings which determine what the trigger does and under what circumstances. {| class="wikitable" |+ |- ! Trigger setting !! Description |- | Active from cycle || The minimum total cycle requirement for the trigger to activate. |- | Active up to cycle || The maximum cycle limit for the trigger to activate - if the player has a cycle count higher than this number, the trigger will not activate. |- | Fire chance || A random percentage chance for the trigger to activate, from 0% to 100%. |- | Trigger delay || How many seconds between the requirements for the trigger being met and the event occurring. |- | Karma req || The minimum karma the player needs for the trigger to activate (from 0 to 5) |- | Can only fire once/Can fire multiple times || Self-explanatory, determines whether the trigger only fires once or not. |- | No entrance requirement/Entrance XX || Determines whether the player can enter from any entrance pipe, or whether they need to come through a specific one. When an entrance is selected, a red line will connect this entrance and the options box. |- | White, Yellow, Red || Determines which gamemodes the trigger fires on - Survivor, Hunter or Monk. A gamemode’s name being displayed means that the trigger will fire in said gamemode. |} === Event Types === The lowest button on the options box lets you pick what type of event you want to add. ==== MusicEvent ==== Plays a song from the soundtrack. * The first button lets you pick the song you want to play. Files for these songs can be found in *Rain World, or many of them can be found [https://www.youtube.com/playlist?list=PLPJWSVeszYFBo1oAXYgzGfJfewnGKgGna online.] {| class="wikitable" |+ MusicEvent options |- ! Option !! Description |- | Play volume || The volume the song plays at. |- | Fade in || In seconds, how long the song takes to reach full volume. |- | Song priority || If this song’s priority is higher than another’s, then this song will continue to play if the other trigger is activated. If the priority is lower, then the higher one will play instead of it. |- | Drone volume || WIP, presumably adds a background drone sound at the set volume. |- | Fade out at threat || The threat level at which the song fades out and is overtaken by the threat music. |- | Rest cycles || If this trigger can activate multiple times, the number of cycles for the trigger to wait before being able to fire again. |- | Room transitions || How many rooms the song will continue playing through. |- | One song per cycle || Whether or not the same song can activate multiple times in one cycle. |- | Play once/loop || Determines whether the song plays once or loops |- | Continue at death || Continue playing the song when the player dies. |- | Continue through gate || Continue playing the song when the player uses a region gate. |} ==== StopMusicEvent ==== As the name says, stops one or more MusicEvents. The first button lets you pick the song you want to stop/exclude. * '''Priority:''' If a song has a higher priority than the trigger, it won’t stop. * '''Fade out:''' Same as fade in, but fading out to silence. * '''Stop all songs/stop specific song/stop all but specific song:''' Self-explanatory, song selected at the top of the box is what this refers to. ==== '''PoleMimicSubtleReveal''' ==== Causes a pole mimic to flutter slightly when activated. ==== '''ShowProjectedImageEvent''' ==== Shows player guide overseer projections ==== '''RoomSpecificTextMessage''' ==== Causes specific text prompt to appear. Prompts are hardcoded by room name {{Cn}} ==== '''BringPlayerGuideToRoom''' ==== Forces player overseer to current room === Trigger Types === * '''Spot:''' The most commonly used trigger; activates when slugcat walks into a specific circular area of the room. This is indicated by a white area-of-effect which can be moved and scaled. * '''SeeCreature:''' ''WIP, presumably activates upon a certain creature being seen.'' * '''RegionBump:''' Activates either when the region is entered or at the beginning of a cycle where the region name and cycle count is shown. * '''PreRegionBump:''' Seemingly functions the same way as RegionBump. </tabber> </div> [[Category:Dev Tools]] 84a65b6b0b1a515342fe068d94ce6dd9129dabf1 317 314 2022-08-27T19:12:39Z Tronsx 19 /* Interface Tabs */ wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ==Interface Tabs== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. <div class="wikitable"><tabber> |-| Room settings= This tab mostly contains settings for base room visuals, such as palette, cloud cover and terrain wetness. === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === [[File:Fadepalette example.png]] ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image on the right shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! {|class="wikitable" |- ! '''Effect''' !! '''Description''' !! '''Showcase''' |- | SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. || [[File:Effect 1.png|frameless|The effect at 100%]] |- | SkyBloom || Increases how fuzzy/bloomy the sky's light is. || [[File:Effect 2.png|frameless]] |- | LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. || [[File:Effect 3.png|frameless]] |- | Bloom || Similar to SkyBloom, but applies to lights. |- | Fog || Creates a white cloudy effect at layer 1. Not compatible with |- | Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- |- | GreenSparks || Underhang, and the Legs' green sparkles. |- | VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | Flies || Spawns small flys that buzz around the room and land on objects. |- | FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | TinyDragonFly || Spawns tiny bugs that fly around plants. |- | RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | Ant || Spawns small jumping bugs. |- | Beetle || Spawns small beetles that slowly fly around the room. |- | WaterGlowWorm || Spawns small worms that swim around in water. |- | Wasp || Spawns small wasps that quickly dart between walls. |- | Moth || Spawns small white moths which slowly flutter around the room. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom`, VoidMelt </syntaxhighlight> |-| Objects= Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds= [[File:soundTab.png|400px|right|border|]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map= {{todo|target=tab}} [[File:mapTab.png|400px|right|border|]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections.png|400px|right|border|Connections on dev map]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png|400px|right|border|Canon view of the map]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png|400px|right|border|Example of a rendered map .png file]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers= {{todo|target=tab}} [[File:triggerTab.png|600px|right|border|Trigger tab view]] <span id="general-controls"></span> == General controls == === Save === Saves the current effects and room settings to a file inside the region’s World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by pressing R and returning to the room to see the changes. === Inherent from template === Will set the values stored in a specific template the region has to this room. === Save as template: === Saves the current room’s settings as a template for easy re-use. == Triggers Menu == '''Triggers''' are the mechanism in which some in-game events occur, such as specific songs playing, projections being displayed by the player guide overseer, or information text being displayed at the bottom of the screen. Clicking one of the four options in the bottom right-hand box will place a trigger of that type, which can be moved just like other devtools objects. === Trigger Options === Triggers have a number of settings which determine what the trigger does and under what circumstances. {| class="wikitable" |+ |- ! Trigger setting !! Description |- | Active from cycle || The minimum total cycle requirement for the trigger to activate. |- | Active up to cycle || The maximum cycle limit for the trigger to activate - if the player has a cycle count higher than this number, the trigger will not activate. |- | Fire chance || A random percentage chance for the trigger to activate, from 0% to 100%. |- | Trigger delay || How many seconds between the requirements for the trigger being met and the event occurring. |- | Karma req || The minimum karma the player needs for the trigger to activate (from 0 to 5) |- | Can only fire once/Can fire multiple times || Self-explanatory, determines whether the trigger only fires once or not. |- | No entrance requirement/Entrance XX || Determines whether the player can enter from any entrance pipe, or whether they need to come through a specific one. When an entrance is selected, a red line will connect this entrance and the options box. |- | White, Yellow, Red || Determines which gamemodes the trigger fires on - Survivor, Hunter or Monk. A gamemode’s name being displayed means that the trigger will fire in said gamemode. |} === Event Types === The lowest button on the options box lets you pick what type of event you want to add. ==== MusicEvent ==== Plays a song from the soundtrack. * The first button lets you pick the song you want to play. Files for these songs can be found in *Rain World, or many of them can be found [https://www.youtube.com/playlist?list=PLPJWSVeszYFBo1oAXYgzGfJfewnGKgGna online.] {| class="wikitable" |+ MusicEvent options |- ! Option !! Description |- | Play volume || The volume the song plays at. |- | Fade in || In seconds, how long the song takes to reach full volume. |- | Song priority || If this song’s priority is higher than another’s, then this song will continue to play if the other trigger is activated. If the priority is lower, then the higher one will play instead of it. |- | Drone volume || WIP, presumably adds a background drone sound at the set volume. |- | Fade out at threat || The threat level at which the song fades out and is overtaken by the threat music. |- | Rest cycles || If this trigger can activate multiple times, the number of cycles for the trigger to wait before being able to fire again. |- | Room transitions || How many rooms the song will continue playing through. |- | One song per cycle || Whether or not the same song can activate multiple times in one cycle. |- | Play once/loop || Determines whether the song plays once or loops |- | Continue at death || Continue playing the song when the player dies. |- | Continue through gate || Continue playing the song when the player uses a region gate. |} ==== StopMusicEvent ==== As the name says, stops one or more MusicEvents. The first button lets you pick the song you want to stop/exclude. * '''Priority:''' If a song has a higher priority than the trigger, it won’t stop. * '''Fade out:''' Same as fade in, but fading out to silence. * '''Stop all songs/stop specific song/stop all but specific song:''' Self-explanatory, song selected at the top of the box is what this refers to. ==== '''PoleMimicSubtleReveal''' ==== Causes a pole mimic to flutter slightly when activated. ==== '''ShowProjectedImageEvent''' ==== Shows player guide overseer projections ==== '''RoomSpecificTextMessage''' ==== Causes specific text prompt to appear. Prompts are hardcoded by room name {{Cn}} ==== '''BringPlayerGuideToRoom''' ==== Forces player overseer to current room === Trigger Types === * '''Spot:''' The most commonly used trigger; activates when slugcat walks into a specific circular area of the room. This is indicated by a white area-of-effect which can be moved and scaled. * '''SeeCreature:''' ''WIP, presumably activates upon a certain creature being seen.'' * '''RegionBump:''' Activates either when the region is entered or at the beginning of a cycle where the region name and cycle count is shown. * '''PreRegionBump:''' Seemingly functions the same way as RegionBump. </tabber> </div> [[Category:Dev Tools]] 24315354261aede61b349c7c2d541e2b4998177b 318 317 2022-08-27T19:17:07Z Tronsx 19 /* Interface Tabs */ wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ==Interface Tabs== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. <div class="wikitable"><tabber> |-| Room settings= This tab mostly contains settings for base room visuals, such as palette, cloud cover and terrain wetness. === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === [[File:Fadepalette example.png]] ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image on the right shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! {|class="wikitable" |- ! '''Effect''' !! '''Description''' !! '''Showcase''' |- | SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. || [[File:Effect 1.png|frameless|The effect at 100%]] |- | SkyBloom || Increases how fuzzy/bloomy the sky's light is. || [[File:Effect 2.png|frameless|Applying the effect]] |- | LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. || [[File:Effect 3.png|frameless|Applying the effect]] |- | Bloom || Similar to SkyBloom, but applies to lights. |- | Fog || Creates a white cloudy effect at layer 1. Not compatible with |- | Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- |- | GreenSparks || Underhang, and the Legs' green sparkles. |- | VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | Flies || Spawns small flys that buzz around the room and land on objects. |- | FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | TinyDragonFly || Spawns tiny bugs that fly around plants. |- | RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | Ant || Spawns small jumping bugs. |- | Beetle || Spawns small beetles that slowly fly around the room. |- | WaterGlowWorm || Spawns small worms that swim around in water. |- | Wasp || Spawns small wasps that quickly dart between walls. |- | Moth || Spawns small white moths which slowly flutter around the room. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom`, VoidMelt </syntaxhighlight> |-| Objects= Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds= [[File:soundTab.png|400px|right|border|]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map= {{todo|target=tab}} [[File:mapTab.png|400px|right|border|]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections.png|400px|right|border|Connections on dev map]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png|400px|right|border|Canon view of the map]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png|400px|right|border|Example of a rendered map .png file]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers= {{todo|target=tab}} [[File:triggerTab.png|600px|right|border|Trigger tab view]] <span id="general-controls"></span> == General controls == === Save === Saves the current effects and room settings to a file inside the region’s World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by pressing R and returning to the room to see the changes. === Inherent from template === Will set the values stored in a specific template the region has to this room. === Save as template: === Saves the current room’s settings as a template for easy re-use. == Triggers Menu == '''Triggers''' are the mechanism in which some in-game events occur, such as specific songs playing, projections being displayed by the player guide overseer, or information text being displayed at the bottom of the screen. Clicking one of the four options in the bottom right-hand box will place a trigger of that type, which can be moved just like other devtools objects. === Trigger Options === Triggers have a number of settings which determine what the trigger does and under what circumstances. {| class="wikitable" |+ |- ! Trigger setting !! Description |- | Active from cycle || The minimum total cycle requirement for the trigger to activate. |- | Active up to cycle || The maximum cycle limit for the trigger to activate - if the player has a cycle count higher than this number, the trigger will not activate. |- | Fire chance || A random percentage chance for the trigger to activate, from 0% to 100%. |- | Trigger delay || How many seconds between the requirements for the trigger being met and the event occurring. |- | Karma req || The minimum karma the player needs for the trigger to activate (from 0 to 5) |- | Can only fire once/Can fire multiple times || Self-explanatory, determines whether the trigger only fires once or not. |- | No entrance requirement/Entrance XX || Determines whether the player can enter from any entrance pipe, or whether they need to come through a specific one. When an entrance is selected, a red line will connect this entrance and the options box. |- | White, Yellow, Red || Determines which gamemodes the trigger fires on - Survivor, Hunter or Monk. A gamemode’s name being displayed means that the trigger will fire in said gamemode. |} === Event Types === The lowest button on the options box lets you pick what type of event you want to add. ==== MusicEvent ==== Plays a song from the soundtrack. * The first button lets you pick the song you want to play. Files for these songs can be found in *Rain World, or many of them can be found [https://www.youtube.com/playlist?list=PLPJWSVeszYFBo1oAXYgzGfJfewnGKgGna online.] {| class="wikitable" |+ MusicEvent options |- ! Option !! Description |- | Play volume || The volume the song plays at. |- | Fade in || In seconds, how long the song takes to reach full volume. |- | Song priority || If this song’s priority is higher than another’s, then this song will continue to play if the other trigger is activated. If the priority is lower, then the higher one will play instead of it. |- | Drone volume || WIP, presumably adds a background drone sound at the set volume. |- | Fade out at threat || The threat level at which the song fades out and is overtaken by the threat music. |- | Rest cycles || If this trigger can activate multiple times, the number of cycles for the trigger to wait before being able to fire again. |- | Room transitions || How many rooms the song will continue playing through. |- | One song per cycle || Whether or not the same song can activate multiple times in one cycle. |- | Play once/loop || Determines whether the song plays once or loops |- | Continue at death || Continue playing the song when the player dies. |- | Continue through gate || Continue playing the song when the player uses a region gate. |} ==== StopMusicEvent ==== As the name says, stops one or more MusicEvents. The first button lets you pick the song you want to stop/exclude. * '''Priority:''' If a song has a higher priority than the trigger, it won’t stop. * '''Fade out:''' Same as fade in, but fading out to silence. * '''Stop all songs/stop specific song/stop all but specific song:''' Self-explanatory, song selected at the top of the box is what this refers to. ==== '''PoleMimicSubtleReveal''' ==== Causes a pole mimic to flutter slightly when activated. ==== '''ShowProjectedImageEvent''' ==== Shows player guide overseer projections ==== '''RoomSpecificTextMessage''' ==== Causes specific text prompt to appear. Prompts are hardcoded by room name {{Cn}} ==== '''BringPlayerGuideToRoom''' ==== Forces player overseer to current room === Trigger Types === * '''Spot:''' The most commonly used trigger; activates when slugcat walks into a specific circular area of the room. This is indicated by a white area-of-effect which can be moved and scaled. * '''SeeCreature:''' ''WIP, presumably activates upon a certain creature being seen.'' * '''RegionBump:''' Activates either when the region is entered or at the beginning of a cycle where the region name and cycle count is shown. * '''PreRegionBump:''' Seemingly functions the same way as RegionBump. </tabber> </div> [[Category:Dev Tools]] 54d821b333ca185cd01ad7a44355e9e9b950c146 320 318 2022-08-27T19:44:25Z Tronsx 19 /* Interface Tabs */ wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ==Interface Tabs== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. <div class="wikitable"><tabber> |-| Room settings= This tab mostly contains settings for base room visuals, such as palette, cloud cover and terrain wetness. === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === [[File:Fadepalette example.png]] ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image on the right shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! {|class="wikitable" |- ! '''Effect''' !! '''Description''' !! '''Showcase''' |- | SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. || [[File:Effect 1.png|frameless|The effect at 100%]] |- | SkyBloom || Increases how fuzzy/bloomy the sky's light is. || [[File:Effect 2.png|frameless|Applying the effect]] |- | LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. || |- | Bloom || Similar to SkyBloom, but applies to lights. || [[File:Effect 4.gif|frameless|Applying the effect]] |- | Fog || Creates a white cloudy effect at layer 1. Not compatible with |- | Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- |- | GreenSparks || Underhang, and the Legs' green sparkles. |- | VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | Flies || Spawns small flys that buzz around the room and land on objects. |- | FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | TinyDragonFly || Spawns tiny bugs that fly around plants. |- | RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | Ant || Spawns small jumping bugs. |- | Beetle || Spawns small beetles that slowly fly around the room. |- | WaterGlowWorm || Spawns small worms that swim around in water. |- | Wasp || Spawns small wasps that quickly dart between walls. |- | Moth || Spawns small white moths which slowly flutter around the room. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom`, VoidMelt </syntaxhighlight> |-| Objects= Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds= [[File:soundTab.png|400px|right|border|]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map= {{todo|target=tab}} [[File:mapTab.png|400px|right|border|]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections.png|400px|right|border|Connections on dev map]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png|400px|right|border|Canon view of the map]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png|400px|right|border|Example of a rendered map .png file]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers= {{todo|target=tab}} [[File:triggerTab.png|600px|right|border|Trigger tab view]] <span id="general-controls"></span> == General controls == === Save === Saves the current effects and room settings to a file inside the region’s World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by pressing R and returning to the room to see the changes. === Inherent from template === Will set the values stored in a specific template the region has to this room. === Save as template: === Saves the current room’s settings as a template for easy re-use. == Triggers Menu == '''Triggers''' are the mechanism in which some in-game events occur, such as specific songs playing, projections being displayed by the player guide overseer, or information text being displayed at the bottom of the screen. Clicking one of the four options in the bottom right-hand box will place a trigger of that type, which can be moved just like other devtools objects. === Trigger Options === Triggers have a number of settings which determine what the trigger does and under what circumstances. {| class="wikitable" |+ |- ! Trigger setting !! Description |- | Active from cycle || The minimum total cycle requirement for the trigger to activate. |- | Active up to cycle || The maximum cycle limit for the trigger to activate - if the player has a cycle count higher than this number, the trigger will not activate. |- | Fire chance || A random percentage chance for the trigger to activate, from 0% to 100%. |- | Trigger delay || How many seconds between the requirements for the trigger being met and the event occurring. |- | Karma req || The minimum karma the player needs for the trigger to activate (from 0 to 5) |- | Can only fire once/Can fire multiple times || Self-explanatory, determines whether the trigger only fires once or not. |- | No entrance requirement/Entrance XX || Determines whether the player can enter from any entrance pipe, or whether they need to come through a specific one. When an entrance is selected, a red line will connect this entrance and the options box. |- | White, Yellow, Red || Determines which gamemodes the trigger fires on - Survivor, Hunter or Monk. A gamemode’s name being displayed means that the trigger will fire in said gamemode. |} === Event Types === The lowest button on the options box lets you pick what type of event you want to add. ==== MusicEvent ==== Plays a song from the soundtrack. * The first button lets you pick the song you want to play. Files for these songs can be found in *Rain World, or many of them can be found [https://www.youtube.com/playlist?list=PLPJWSVeszYFBo1oAXYgzGfJfewnGKgGna online.] {| class="wikitable" |+ MusicEvent options |- ! Option !! Description |- | Play volume || The volume the song plays at. |- | Fade in || In seconds, how long the song takes to reach full volume. |- | Song priority || If this song’s priority is higher than another’s, then this song will continue to play if the other trigger is activated. If the priority is lower, then the higher one will play instead of it. |- | Drone volume || WIP, presumably adds a background drone sound at the set volume. |- | Fade out at threat || The threat level at which the song fades out and is overtaken by the threat music. |- | Rest cycles || If this trigger can activate multiple times, the number of cycles for the trigger to wait before being able to fire again. |- | Room transitions || How many rooms the song will continue playing through. |- | One song per cycle || Whether or not the same song can activate multiple times in one cycle. |- | Play once/loop || Determines whether the song plays once or loops |- | Continue at death || Continue playing the song when the player dies. |- | Continue through gate || Continue playing the song when the player uses a region gate. |} ==== StopMusicEvent ==== As the name says, stops one or more MusicEvents. The first button lets you pick the song you want to stop/exclude. * '''Priority:''' If a song has a higher priority than the trigger, it won’t stop. * '''Fade out:''' Same as fade in, but fading out to silence. * '''Stop all songs/stop specific song/stop all but specific song:''' Self-explanatory, song selected at the top of the box is what this refers to. ==== '''PoleMimicSubtleReveal''' ==== Causes a pole mimic to flutter slightly when activated. ==== '''ShowProjectedImageEvent''' ==== Shows player guide overseer projections ==== '''RoomSpecificTextMessage''' ==== Causes specific text prompt to appear. Prompts are hardcoded by room name {{Cn}} ==== '''BringPlayerGuideToRoom''' ==== Forces player overseer to current room === Trigger Types === * '''Spot:''' The most commonly used trigger; activates when slugcat walks into a specific circular area of the room. This is indicated by a white area-of-effect which can be moved and scaled. * '''SeeCreature:''' ''WIP, presumably activates upon a certain creature being seen.'' * '''RegionBump:''' Activates either when the region is entered or at the beginning of a cycle where the region name and cycle count is shown. * '''PreRegionBump:''' Seemingly functions the same way as RegionBump. </tabber> </div> [[Category:Dev Tools]] d7bab3b4583bb91c36ebe00321844999f02aa386 324 320 2022-08-30T00:38:01Z Tronsx 19 /* Interface Tabs */ wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ==Interface Tabs== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. <div class="wikitable"><tabber> |-| Room settings= This tab mostly contains settings for base room visuals, such as palette, cloud cover and terrain wetness. === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === [[File:Fadepalette example.png]] ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image on the right shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! {|class="wikitable" |- ! '''Effect''' !! '''Description''' !! '''Showcase''' |- | SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. || [[File:Effect 1.png|frameless|The effect at 100%]] |- | SkyBloom || Increases how fuzzy/bloomy the sky's light is. || [[File:Effect 2.png|frameless|Applying the effect]] |- | LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. || [[File:Effect 3.png|frameless]] |- | Bloom || Similar to SkyBloom, but applies to lights. || [[File:Effect 4.gif|frameless|Applying the effect]] |- | Fog || Creates a white cloudy effect at layer 1. Not compatible with |- | Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- |- | GreenSparks || Underhang, and the Legs' green sparkles. |- | VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | Flies || Spawns small flys that buzz around the room and land on objects. |- | FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | TinyDragonFly || Spawns tiny bugs that fly around plants. |- | RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | Ant || Spawns small jumping bugs. |- | Beetle || Spawns small beetles that slowly fly around the room. |- | WaterGlowWorm || Spawns small worms that swim around in water. |- | Wasp || Spawns small wasps that quickly dart between walls. |- | Moth || Spawns small white moths which slowly flutter around the room. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom`, VoidMelt </syntaxhighlight> |-| Objects= Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds= [[File:soundTab.png|400px|right|border|]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map= {{todo|target=tab}} [[File:mapTab.png|400px|right|border|]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections.png|400px|right|border|Connections on dev map]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png|400px|right|border|Canon view of the map]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png|400px|right|border|Example of a rendered map .png file]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers= {{todo|target=tab}} [[File:triggerTab.png|600px|right|border|Trigger tab view]] <span id="general-controls"></span> == General controls == === Save === Saves the current effects and room settings to a file inside the region’s World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by pressing R and returning to the room to see the changes. === Inherent from template === Will set the values stored in a specific template the region has to this room. === Save as template: === Saves the current room’s settings as a template for easy re-use. == Triggers Menu == '''Triggers''' are the mechanism in which some in-game events occur, such as specific songs playing, projections being displayed by the player guide overseer, or information text being displayed at the bottom of the screen. Clicking one of the four options in the bottom right-hand box will place a trigger of that type, which can be moved just like other devtools objects. === Trigger Options === Triggers have a number of settings which determine what the trigger does and under what circumstances. {| class="wikitable" |+ |- ! Trigger setting !! Description |- | Active from cycle || The minimum total cycle requirement for the trigger to activate. |- | Active up to cycle || The maximum cycle limit for the trigger to activate - if the player has a cycle count higher than this number, the trigger will not activate. |- | Fire chance || A random percentage chance for the trigger to activate, from 0% to 100%. |- | Trigger delay || How many seconds between the requirements for the trigger being met and the event occurring. |- | Karma req || The minimum karma the player needs for the trigger to activate (from 0 to 5) |- | Can only fire once/Can fire multiple times || Self-explanatory, determines whether the trigger only fires once or not. |- | No entrance requirement/Entrance XX || Determines whether the player can enter from any entrance pipe, or whether they need to come through a specific one. When an entrance is selected, a red line will connect this entrance and the options box. |- | White, Yellow, Red || Determines which gamemodes the trigger fires on - Survivor, Hunter or Monk. A gamemode’s name being displayed means that the trigger will fire in said gamemode. |} === Event Types === The lowest button on the options box lets you pick what type of event you want to add. ==== MusicEvent ==== Plays a song from the soundtrack. * The first button lets you pick the song you want to play. Files for these songs can be found in *Rain World, or many of them can be found [https://www.youtube.com/playlist?list=PLPJWSVeszYFBo1oAXYgzGfJfewnGKgGna online.] {| class="wikitable" |+ MusicEvent options |- ! Option !! Description |- | Play volume || The volume the song plays at. |- | Fade in || In seconds, how long the song takes to reach full volume. |- | Song priority || If this song’s priority is higher than another’s, then this song will continue to play if the other trigger is activated. If the priority is lower, then the higher one will play instead of it. |- | Drone volume || WIP, presumably adds a background drone sound at the set volume. |- | Fade out at threat || The threat level at which the song fades out and is overtaken by the threat music. |- | Rest cycles || If this trigger can activate multiple times, the number of cycles for the trigger to wait before being able to fire again. |- | Room transitions || How many rooms the song will continue playing through. |- | One song per cycle || Whether or not the same song can activate multiple times in one cycle. |- | Play once/loop || Determines whether the song plays once or loops |- | Continue at death || Continue playing the song when the player dies. |- | Continue through gate || Continue playing the song when the player uses a region gate. |} ==== StopMusicEvent ==== As the name says, stops one or more MusicEvents. The first button lets you pick the song you want to stop/exclude. * '''Priority:''' If a song has a higher priority than the trigger, it won’t stop. * '''Fade out:''' Same as fade in, but fading out to silence. * '''Stop all songs/stop specific song/stop all but specific song:''' Self-explanatory, song selected at the top of the box is what this refers to. ==== '''PoleMimicSubtleReveal''' ==== Causes a pole mimic to flutter slightly when activated. ==== '''ShowProjectedImageEvent''' ==== Shows player guide overseer projections ==== '''RoomSpecificTextMessage''' ==== Causes specific text prompt to appear. Prompts are hardcoded by room name {{Cn}} ==== '''BringPlayerGuideToRoom''' ==== Forces player overseer to current room === Trigger Types === * '''Spot:''' The most commonly used trigger; activates when slugcat walks into a specific circular area of the room. This is indicated by a white area-of-effect which can be moved and scaled. * '''SeeCreature:''' ''WIP, presumably activates upon a certain creature being seen.'' * '''RegionBump:''' Activates either when the region is entered or at the beginning of a cycle where the region name and cycle count is shown. * '''PreRegionBump:''' Seemingly functions the same way as RegionBump. </tabber> </div> [[Category:Dev Tools]] f50d89df0363df7fa4443f3463f0afb7907a7c52 327 324 2022-08-30T01:03:48Z Tronsx 19 wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ==Interface Tabs== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. <div class="wikitable"><tabber> |-| Room settings= This tab mostly contains settings for base room visuals, such as palette, cloud cover and terrain wetness. === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === [[File:Fadepalette example.png]] ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image on the right shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! {|class="wikitable" |- ! '''Effect''' !! '''Description''' !! '''Showcase''' |- | SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. || [[File:Effect 1.png|frameless|The effect at 100%]] |- | SkyBloom || Increases how fuzzy/bloomy the sky's light is. || [[File:Effect 2.png|frameless|Applying the effect]] |- | LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. || [[File:Effect 3.png|frameless]] |- | SkyAndLightBloom || A mix between skybloom and light burn at the same time is more intense. || [[File:Effect 4.gif|frameless|Applying the effect]] |- | Bloom || Similar to SkyBloom, but applies to lights. || [[File:Effect 5.png|frameless]] |- | Fog || Creates a white cloudy effect at layer 1. Not compatible with SkyBloom, LightBurn, SkyAndLightBloom and Bloom. || [[File:Effect 6.png|frameless]] |- | Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- |- | GreenSparks || Underhang, and the Legs' green sparkles. |- | VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | Flies || Spawns small flys that buzz around the room and land on objects. |- | FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | TinyDragonFly || Spawns tiny bugs that fly around plants. |- | RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | Ant || Spawns small jumping bugs. |- | Beetle || Spawns small beetles that slowly fly around the room. |- | WaterGlowWorm || Spawns small worms that swim around in water. |- | Wasp || Spawns small wasps that quickly dart between walls. |- | Moth || Spawns small white moths which slowly flutter around the room. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom, VoidMelt </syntaxhighlight> |-| Objects= Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds= [[File:soundTab.png|400px|right|border|]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map= {{todo|target=tab}} [[File:mapTab.png|400px|right|border|]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections.png|400px|right|border|Connections on dev map]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png|400px|right|border|Canon view of the map]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png|400px|right|border|Example of a rendered map .png file]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers= {{todo|target=tab}} [[File:triggerTab.png|600px|right|border|Trigger tab view]] <span id="general-controls"></span> == General controls == === Save === Saves the current effects and room settings to a file inside the region’s World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by pressing R and returning to the room to see the changes. === Inherent from template === Will set the values stored in a specific template the region has to this room. === Save as template: === Saves the current room’s settings as a template for easy re-use. == Triggers Menu == '''Triggers''' are the mechanism in which some in-game events occur, such as specific songs playing, projections being displayed by the player guide overseer, or information text being displayed at the bottom of the screen. Clicking one of the four options in the bottom right-hand box will place a trigger of that type, which can be moved just like other devtools objects. === Trigger Options === Triggers have a number of settings which determine what the trigger does and under what circumstances. {| class="wikitable" |+ |- ! Trigger setting !! Description |- | Active from cycle || The minimum total cycle requirement for the trigger to activate. |- | Active up to cycle || The maximum cycle limit for the trigger to activate - if the player has a cycle count higher than this number, the trigger will not activate. |- | Fire chance || A random percentage chance for the trigger to activate, from 0% to 100%. |- | Trigger delay || How many seconds between the requirements for the trigger being met and the event occurring. |- | Karma req || The minimum karma the player needs for the trigger to activate (from 0 to 5) |- | Can only fire once/Can fire multiple times || Self-explanatory, determines whether the trigger only fires once or not. |- | No entrance requirement/Entrance XX || Determines whether the player can enter from any entrance pipe, or whether they need to come through a specific one. When an entrance is selected, a red line will connect this entrance and the options box. |- | White, Yellow, Red || Determines which gamemodes the trigger fires on - Survivor, Hunter or Monk. A gamemode’s name being displayed means that the trigger will fire in said gamemode. |} === Event Types === The lowest button on the options box lets you pick what type of event you want to add. ==== MusicEvent ==== Plays a song from the soundtrack. * The first button lets you pick the song you want to play. Files for these songs can be found in *Rain World, or many of them can be found [https://www.youtube.com/playlist?list=PLPJWSVeszYFBo1oAXYgzGfJfewnGKgGna online.] {| class="wikitable" |+ MusicEvent options |- ! Option !! Description |- | Play volume || The volume the song plays at. |- | Fade in || In seconds, how long the song takes to reach full volume. |- | Song priority || If this song’s priority is higher than another’s, then this song will continue to play if the other trigger is activated. If the priority is lower, then the higher one will play instead of it. |- | Drone volume || WIP, presumably adds a background drone sound at the set volume. |- | Fade out at threat || The threat level at which the song fades out and is overtaken by the threat music. |- | Rest cycles || If this trigger can activate multiple times, the number of cycles for the trigger to wait before being able to fire again. |- | Room transitions || How many rooms the song will continue playing through. |- | One song per cycle || Whether or not the same song can activate multiple times in one cycle. |- | Play once/loop || Determines whether the song plays once or loops |- | Continue at death || Continue playing the song when the player dies. |- | Continue through gate || Continue playing the song when the player uses a region gate. |} ==== StopMusicEvent ==== As the name says, stops one or more MusicEvents. The first button lets you pick the song you want to stop/exclude. * '''Priority:''' If a song has a higher priority than the trigger, it won’t stop. * '''Fade out:''' Same as fade in, but fading out to silence. * '''Stop all songs/stop specific song/stop all but specific song:''' Self-explanatory, song selected at the top of the box is what this refers to. ==== '''PoleMimicSubtleReveal''' ==== Causes a pole mimic to flutter slightly when activated. ==== '''ShowProjectedImageEvent''' ==== Shows player guide overseer projections ==== '''RoomSpecificTextMessage''' ==== Causes specific text prompt to appear. Prompts are hardcoded by room name {{Cn}} ==== '''BringPlayerGuideToRoom''' ==== Forces player overseer to current room === Trigger Types === * '''Spot:''' The most commonly used trigger; activates when slugcat walks into a specific circular area of the room. This is indicated by a white area-of-effect which can be moved and scaled. * '''SeeCreature:''' ''WIP, presumably activates upon a certain creature being seen.'' * '''RegionBump:''' Activates either when the region is entered or at the beginning of a cycle where the region name and cycle count is shown. * '''PreRegionBump:''' Seemingly functions the same way as RegionBump. </tabber> </div> [[Category:Dev Tools]] 6fc47a1464f25192aab17482b763faaa2fdb56f0 333 327 2022-09-08T14:04:31Z Cashewww 2 added debugmouse page link wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. A tip for expanding functionality can be found on the [[DebugMouse]] page. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ==Interface Tabs== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. <div class="wikitable"><tabber> |-| Room settings= This tab mostly contains settings for base room visuals, such as palette, cloud cover and terrain wetness. === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === [[File:Fadepalette example.png]] ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image on the right shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! {|class="wikitable" |- ! '''Effect''' !! '''Description''' !! '''Showcase''' |- | SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. || [[File:Effect 1.png|frameless|The effect at 100%]] |- | SkyBloom || Increases how fuzzy/bloomy the sky's light is. || [[File:Effect 2.png|frameless|Applying the effect]] |- | LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. || [[File:Effect 3.png|frameless]] |- | SkyAndLightBloom || A mix between skybloom and light burn at the same time is more intense. || [[File:Effect 4.gif|frameless|Applying the effect]] |- | Bloom || Similar to SkyBloom, but applies to lights. || [[File:Effect 5.png|frameless]] |- | Fog || Creates a white cloudy effect at layer 1. Not compatible with SkyBloom, LightBurn, SkyAndLightBloom and Bloom. || [[File:Effect 6.png|frameless]] |- | Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- |- | GreenSparks || Underhang, and the Legs' green sparkles. |- | VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | Flies || Spawns small flys that buzz around the room and land on objects. |- | FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | TinyDragonFly || Spawns tiny bugs that fly around plants. |- | RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | Ant || Spawns small jumping bugs. |- | Beetle || Spawns small beetles that slowly fly around the room. |- | WaterGlowWorm || Spawns small worms that swim around in water. |- | Wasp || Spawns small wasps that quickly dart between walls. |- | Moth || Spawns small white moths which slowly flutter around the room. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom, VoidMelt </syntaxhighlight> |-| Objects= Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds= [[File:soundTab.png|400px|right|border|]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map= {{todo|target=tab}} [[File:mapTab.png|400px|right|border|]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections.png|400px|right|border|Connections on dev map]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png|400px|right|border|Canon view of the map]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png|400px|right|border|Example of a rendered map .png file]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers= {{todo|target=tab}} [[File:triggerTab.png|600px|right|border|Trigger tab view]] <span id="general-controls"></span> == General controls == === Save === Saves the current effects and room settings to a file inside the region’s World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by pressing R and returning to the room to see the changes. === Inherent from template === Will set the values stored in a specific template the region has to this room. === Save as template: === Saves the current room’s settings as a template for easy re-use. == Triggers Menu == '''Triggers''' are the mechanism in which some in-game events occur, such as specific songs playing, projections being displayed by the player guide overseer, or information text being displayed at the bottom of the screen. Clicking one of the four options in the bottom right-hand box will place a trigger of that type, which can be moved just like other devtools objects. === Trigger Options === Triggers have a number of settings which determine what the trigger does and under what circumstances. {| class="wikitable" |+ |- ! Trigger setting !! Description |- | Active from cycle || The minimum total cycle requirement for the trigger to activate. |- | Active up to cycle || The maximum cycle limit for the trigger to activate - if the player has a cycle count higher than this number, the trigger will not activate. |- | Fire chance || A random percentage chance for the trigger to activate, from 0% to 100%. |- | Trigger delay || How many seconds between the requirements for the trigger being met and the event occurring. |- | Karma req || The minimum karma the player needs for the trigger to activate (from 0 to 5) |- | Can only fire once/Can fire multiple times || Self-explanatory, determines whether the trigger only fires once or not. |- | No entrance requirement/Entrance XX || Determines whether the player can enter from any entrance pipe, or whether they need to come through a specific one. When an entrance is selected, a red line will connect this entrance and the options box. |- | White, Yellow, Red || Determines which gamemodes the trigger fires on - Survivor, Hunter or Monk. A gamemode’s name being displayed means that the trigger will fire in said gamemode. |} === Event Types === The lowest button on the options box lets you pick what type of event you want to add. ==== MusicEvent ==== Plays a song from the soundtrack. * The first button lets you pick the song you want to play. Files for these songs can be found in *Rain World, or many of them can be found [https://www.youtube.com/playlist?list=PLPJWSVeszYFBo1oAXYgzGfJfewnGKgGna online.] {| class="wikitable" |+ MusicEvent options |- ! Option !! Description |- | Play volume || The volume the song plays at. |- | Fade in || In seconds, how long the song takes to reach full volume. |- | Song priority || If this song’s priority is higher than another’s, then this song will continue to play if the other trigger is activated. If the priority is lower, then the higher one will play instead of it. |- | Drone volume || WIP, presumably adds a background drone sound at the set volume. |- | Fade out at threat || The threat level at which the song fades out and is overtaken by the threat music. |- | Rest cycles || If this trigger can activate multiple times, the number of cycles for the trigger to wait before being able to fire again. |- | Room transitions || How many rooms the song will continue playing through. |- | One song per cycle || Whether or not the same song can activate multiple times in one cycle. |- | Play once/loop || Determines whether the song plays once or loops |- | Continue at death || Continue playing the song when the player dies. |- | Continue through gate || Continue playing the song when the player uses a region gate. |} ==== StopMusicEvent ==== As the name says, stops one or more MusicEvents. The first button lets you pick the song you want to stop/exclude. * '''Priority:''' If a song has a higher priority than the trigger, it won’t stop. * '''Fade out:''' Same as fade in, but fading out to silence. * '''Stop all songs/stop specific song/stop all but specific song:''' Self-explanatory, song selected at the top of the box is what this refers to. ==== '''PoleMimicSubtleReveal''' ==== Causes a pole mimic to flutter slightly when activated. ==== '''ShowProjectedImageEvent''' ==== Shows player guide overseer projections ==== '''RoomSpecificTextMessage''' ==== Causes specific text prompt to appear. Prompts are hardcoded by room name {{Cn}} ==== '''BringPlayerGuideToRoom''' ==== Forces player overseer to current room === Trigger Types === * '''Spot:''' The most commonly used trigger; activates when slugcat walks into a specific circular area of the room. This is indicated by a white area-of-effect which can be moved and scaled. * '''SeeCreature:''' ''WIP, presumably activates upon a certain creature being seen.'' * '''RegionBump:''' Activates either when the region is entered or at the beginning of a cycle where the region name and cycle count is shown. * '''PreRegionBump:''' Seemingly functions the same way as RegionBump. </tabber> </div> [[Category:Dev Tools]] 5bd6c20c3778b732e21363a49851ddda7d5cc3ae Category:Utilities and Tools 14 131 328 218 2022-09-08T13:43:36Z Cashewww 2 Cashewww moved page [[Category:Utility Mods]] to [[Category:Utilities and Tools]] wikitext text/x-wiki This category is for mods that are good tools for further mod development but aren't a dependencies. abac0f0f1bef32efeb25cd71e8bbcc232c371d21 Category:Utility Mods 14 165 329 2022-09-08T13:43:36Z Cashewww 2 Cashewww moved page [[Category:Utility Mods]] to [[Category:Utilities and Tools]] wikitext text/x-wiki #REDIRECT [[:Category:Utilities and Tools]] aa33853d140d49d404805bb4ecf5df6a780cf54b Warp 0 128 330 211 2022-09-08T13:54:20Z Cashewww 2 updated category wikitext text/x-wiki Warp is a utility mod for Rain World that you can use to easily teleport to different rooms and regions. It is particularly useful for testing mods and [[CRS|region packs]]. Download and install Warp from [https://www.raindb.net/ RainDB] or [https://github.com/LeeMoriya/Warp/releases/latest Warp's GitHub page]. == Usage == [[File:WarpMenu.png|thumb|Region buttons are shown on the left, room buttons are shown on the right. There are also settings for different colour codings and order schemes. ]] Install Warp using [[BepInEx]], and then Warp menu will appear in the in-game pause menu. Clicking on a room button will teleport the player to the room's first entrance pipe (numbered 0). Clicking on a region button (other than the one the player is currently in) will load the region and show a list of its rooms instead. The loading process may take a few seconds if the region is particularly large. === Issues When Warping === If the region doesn't load then there is likely an issue with the region or room you are trying to warp to. Check your [[Logs|exceptionLog]] for errors and review any recent changes you made to the region/rooms. If you are making a custom region, make sure there are no errors with room connections in your World file, or problems with your room's geometry (e.g. invalid pipe entrances). If you have installed/uninstalled a new region, make sure you have started the game from a fresh save since that region was added or the game may freeze when switching regions or resting in a shelter. == Custom Den Position == Warp features and option to change which room the game considers as the player's den position (the room in which they start the next cycle). Note that if you're using [[Extended Dev Tools]], the 'Start Map' parameter in the <code>edtSetup.json</code> must be empty or it will override Warp. * Hold Shift and click a room name to set the den position. * Press C to reset the den position to its default. == Custom Regions Support == Warp supports [[CRS|Garrakx's Custom Regions Support]] mod which allows for easier creation of new regions and region changes, and will load new rooms from within your CustomResources folder. Below is how room lists are currently generated: === Current Region === The lust of rooms for the region you are currently in are taken directly from the list of loaded AbstractRooms. === Different Regions === When you click on a button for a different region, the room list is generated like so: # Rooms are added to the room list from the vanilla World folder. # Each Rooms folder found in CustomResources is scanned and rooms not already in the list are added. At the moment, this means that if a region pack is present in your CustomResources folder but has been manually disabled in its regionInfo.json, rooms from this folder will be regardless and clicking on them will do nothing. This is also technically the case for any region pack that removes rooms. [[Category:Utilities and Tools]] c2dd15fbebd52f992afbccef29e152beac23e1cf Main Page 0 1 331 272 2022-09-08T13:54:56Z Cashewww 2 updated category link wikitext text/x-wiki __NOTOC__ [[File:RWModdingTitle.png|800px|frameless|center]] <br> <div id="intro-text" style="text-align: center;"> '''Welcome!''' The Rain World Modding Wiki is a place to share information about modding the video game, ''Rain World''. For more about the game, check out the '''[https://rainworld.miraheze.org/wiki/Rain_World_Wiki Official Rain World Wiki]'''! This wiki is currently in the process of being ported from an old wiki. To get involved, be sure to check out the modding category in the [https://discord.gg/rainworld Rain World Discord]. </div> == Where to Start... == For instructions for installing mods, see [[Installing Mods]]. For description of architecture changes that will occur with release of Downpour, as well as technical reference for the incoming Remix built-in modloader, see [[Downpour Reference]]. On a technical level, mods can be split into the following families: * [[:Category:Code Mods|Code Mods]] (any mod where the main component is a .dll file) * [[:Category:Content Mods|Content Mods]] (this includes region packs, arenas, etc.). Follow one of the links above to learn more about making these kinds of mods. Sometimes there is overlap. For example a [[Custom Region Support|region pack]] (a type of content mod) may require additional code mods for custom creatures, or a code mod may require additional asset files (though often they are embedded within the dll). If you have questions that the wiki can't yet answer, feel free to ask in the modding category in the [https://discord.gg/rainworld Rain World Discord]. == Contributing == If you have modding knowledge that the wiki doesn't yet have, please do contribute! The following categories contain pages demanding attention: * [[:Category:Cleanup needed]] * [[:Category:Unfinished]] Don't forget to check [[Contribution Guidelines]]. == Quick Links == * [[:Category:Code Mods]] * [[:Category:Content Mods]] * [[:Category:Dev Tools]] * [[:Category:Dependencies]] * [[:Category:Utilities and Tools]] * [[CRS]] * [[Warp]] 2428e9ad40e6923d204dcb0913fc382597fd3f5a DebugMouse 0 166 332 2022-09-08T13:55:27Z Cashewww 2 created page about mouse debugging wikitext text/x-wiki Position/tile debugging tools are included in the game and activatable via [[Dev Tools]]. When active, a text label follows the mouse position around the screen that details infomation such as raw mouse position and in-room tile coordinates. Additional information can be added to this label through use of a code mod that hooks the game's DebugMouse.Update method. For example: <syntaxhighlight lang="csharp"> /// <summary> /// Hook me to On.DebugMouse.Update! /// </summary> private static void DebugMouse_Update(On.DebugMouse.orig_Update orig, DebugMouse self, bool eu) { orig(self, eu); if (!self.room.readyForAI || !self.room.BeingViewed) return; string text = self.label.text; AItile aiTile = self.room.aimap.getAItile(self.pos); text += $"\n\n--aiTile--" + $"acc: {aiTile.acc}\n" + $"floorAltitude: {aiTile.floorAltitude} smoothed: {aiTile.smoothedFloorAltitude}\n" + $"terrain prox: {aiTile.terrainProximity}"; self.label.text = text; self.label2.text = text; } </syntaxhighlight> label2 acts as a shadow to aid readability. [[Category:Code Mods]] [[Category:Dev Tools]] [[Category:Utilities and Tools]] 69bd5091a6ea3f3cd78b1505c420ab9281e86d52 MediaWiki:Common.css 8 24 334 25 2022-09-08T14:11:31Z Cashewww 2 increased heading sizes to distinguish from body text css text/css /* CSS placed here will be applied to all skins */ /* custom theme start */ :root { --bg-color: #151015ea; --bg-color-solid: #151015; --txt-color: #eee; --txt-color-dark: #bbb; --url-color: #fab; --url-color-visited: #c8a; --light-border-color: #fff6; --dark-pink: #867; --dark-green: #676; --table-bg-header: #0009; --table-bg: #0005; --edit-url-color: #c9b; --toc-bg-color: #0002; --toc-num-color: #aaa; --leftnavbar-url-color: #fef; --leftnavbar-header-color: #ddd; --header-bg-color: #12101250; --header-tab-bg: linear-gradient(#302530da,#151015da); --header-tab-color: #eee; --embed-bg: #171017b0; --diff-delete: #955; --diff-add: #595; } /* main */ body { background-color: var(--bg-color-solid); background-image: url(https://static.miraheze.org/rainworldmoddingwiki/e/e4/LandscapeHI.png); background-position: center; background-repeat: no-repeat; background-attachment: fixed; background-size: cover; } .mw-body { background-color: var(--bg-color); color: var(--txt-color); border: 1px solid var(--light-border-color); } .mw-body h1, h2, h3, h4, h5, h6 { color: var(--txt-color); } .mw-body h1 { font-size: 2em; } .mw-body h2 { font-size: 1.6em; } .mw-body h3 { font-size: 1.4em; } .mw-body h4 { font-size: 1.2em; } .mw-body a, .mw-parser-output a.external { color: var(--url-color); } .mw-body a:visited, .mw-parser-output a.external:visited { color: var(--url-color-visited) } .mw-body .mw-editsection a { color: var(--edit-url-color); } ul { list-style: disc; } /* table of contents */ .toc { background-color: var(--toc-bg-color); border-radius: 4px; } .tocnumber { color: var(--toc-num-color); } .toctext { color: var(--leftnavbar-url-color) } /* left nav bar */ #mw-panel { background-color: var(--header-bg-color); } #mw-panel a { color: var(--leftnavbar-url-color); font-weight: 600; } #mw-panel span { color: var(--leftnavbar-header-color); } /* header */ #mw-page-base { background: none; } #mw-head { background-color: var(--header-bg-color); } #mw-head .vector-menu-content-list li { background-image: var(--header-tab-bg); } #mw-head a { color: var(--header-tab-color); } #mw-head #p-personal li { background-image: none; } .oo-ui-icon-tray, .oo-ui-icon-bell { background-color: var(--txt-color); } #mw-head #p-personal #pt-userpage a { color: var(--leftnavbar-url-color); } /* thumbnails and embeds */ .thumbinner, .catlinks { background-color: var(--embed-bg) !important; } .catlinks { border-radius: 4px; } .catlinks a { color: var(--leftnavbar-url-color) } .thumbimage { background-color: var(--embed-bg); } /* infoboxes */ .infoboxtable { float: right; padding: 10px; border: 1px solid var(--txt-color); border-radius: 4px; font-size: 90%; margin-left: 1em; margin-bottom: 0.5em; width: 300px } .infoboxtable td { vertical-align: top } .infoboxtable td > div { background-color: var(--embed-bg); font-weight: bold; padding: 0.5px 7px } .infoboxname { background-color: var(--embed-bg); font-size: 110%; font-weight: bold; padding: 0.4em } .infoboxdetails { background-color: var(--embed-bg); padding: 0.15em; } .infoboxname, .infoboxdetails, .infoboxtable .mw-collapsible th{ border-radius: 2px !important; border: 1px solid #767; } .mw-collapsible th { background-color: var(--embed-bg) !important; } /* file history */ #filetoc { background-color: var(--toc-bg-color); border: 1px solid var(--txt-color); border-radius: 2px; } /* footer */ #footer-info li { color: var(--leftnavbar-header-color); } #footer-info a, #footer-places a { color: var(--leftnavbar-url-color); font-weight: 800; } /* image gallery */ li.gallerybox div.thumb { background-color: var(--toc-bg-color); border-radius: 3px; } /* general tables */ .wikitable { background-color: var(--table-bg-color) !important; color: var(--txt-color) !important; } .wikitable th { background-color: var(--table-bg-header) !important; } /* page history comparer */ #pagehistory li.selected { background-color: transparent; outline: none; color: var(--txt-color); border: 1px dashed var(--txt-color); } /* page diff */ .diff-context { background-color: var(--embed-bg); color: var(--txt-color); } .diff-deletedline { border-color: var(--diff-delete); } .diff-deletedline .diffchange { background-color: var(--diff-delete); } .diff-addedline { border-color: var(--diff-add); } .diff-addedline .diffchange { background-color: var(--diff-add); } /* recent changes page */ .oo-ui-tagMultiselectWidget.oo-ui-widget-enabled.oo-ui-tagMultiselectWidget-outlined .oo-ui-tagItemWidget.oo-ui-widget-enabled, .mw-rcfilters-ui-filterTagMultiselectWidget.oo-ui-widget-enabled .oo-ui-tagMultiselectWidget-handle, .oo-ui-tagMultiselectWidget.oo-ui-widget-enabled.oo-ui-tagMultiselectWidget-outlined, .oo-ui-textInputWidget .oo-ui-inputWidget-input, .mw-rcfilters-ui-changesListWrapperWidget .mw-changeslist-legend { background-color: var(--embed-bg); border-radius: 3px; } .mw-rcfilters-ui-filterTagItemWidget .oo-ui-labelElement-label, .oo-ui-buttonElement-button .oo-ui-labelElement-label { color: var(--txt-color-dark); } .mw-rcfilters-ui-filterWrapperWidget-showNewChanges .oo-ui-labelElement-label, .mw-rcfilters-ui-filterTagMultiselectWidget .oo-ui-labelElement-label { color: var(--txt-color); } /* file metadata and licensing */ .toccolours { background-color: var(--embed-bg); } .fileinfo-paramfield { background-color: var(--bg-color-solid) } .licensetpl_wrapper, .licensetpl, .layouttemplate table { background-color: var(--embed-bg) !important; } #mw_metadata th, #mw_metadata td { background-color: var(--embed-bg); } /* uploaded files list */ .mw-datatable th, .mw-datatable td { background-color: var(--embed-bg); } .mw-datatable tr:hover td { background-color: var(--bg-color-solid); } /* search bar */ #searchInput { background-color: var(--embed-bg); border-color: var(--light-border-color); color: var(--txt-color); } /* deleted pages page text box & email text box */ .oo-ui-textInputWidget .oo-ui-inputWidget-input { color: var(--txt-color); } /* help text (extensions manager, etc.) */ .oo-ui-inline-help { color: var(--txt-color-dark) !important; } /* main page page creator */ .createboxInput { background-color: var(--embed-bg); border-color: var(--txt-color-dark); color: var(--txt-color) } .mw-ui-button.mw-ui-progressive, .mw-ui-button.mw-ui-progressive:disabled { background-color: var(--embed-bg); border: 1px solid var(--txt-color-dark); transition: ease-in-out 0.3s; } .mw-ui-button.mw-ui-progressive:hover, .mw-ui-button.mw-ui-progressive:disabled:hover { background-color: var(--embed-bg); border: 1px solid var(--url-color); } .mw-body-content blockquote { border-left: 2px solid #eaecf040; } /* userprofile extension support */ #profile-image img { background-color: transparent; border-radius: 4px; } .no-info-container, .profile-info-container, .profile-on { background-color: var(--embed-bg); border: 1px solid var(--txt-color); border-radius: 4px; color: var(--txt-color); } .profile-info-container { margin-bottom: 20px; } .profile-info-container div { padding: 10px 20px; color: var(--txt-color); } .profile-info-container div b { color: var(--txt-color-dark); font-size: 0.9em; } #profile-toggle-button, .profile-tab-on, .profile-tab { background-color: var(--embed-bg); border: 1px solid var(--txt-color-dark); border-radius: 3px; } .profile-tab-on { background-color: var(--dark-pink); } .profile-on { background-color: var(--dark-green); color: white; padding: 5px; } .profile-update-title, .profile-update-unit-left { color: var(--txt-color); } .eye-container { opacity: 0.8; } .eye-container .title { color: black; } .eye-container .menu .item, .eye-container .menu .item:hover { color: black; } .tux-editor-header { color: #fff; font-size: 14px; } .group-warning { background: #371425; padding: 5px; margin: 5px 0; } .tux-breadcrumb { color: #fff; font-size: 14pt; line-height: 1.25em; } .tux-breadcrumb__item--aggregate { cursor: pointer; color: #FEF; } .ext-translate-language-selector-label { color: #fff; } .ext-translate-language-selector .uls { color: #FEF; cursor: pointer; min-height: 1px; position: relative; } .toctogglelabel { cursor: pointer; color: #fff; } .jquery-tablesorter th.headerSort { background-image: url(https://static.miraheze.org/rainworldwiki/c/c3/RW_sort_both.svg); background-repeat: no-repeat; background-position: right; padding-right: 21px; background-size: 21px; } .jquery-tablesorter th.headerSortUp { background-image: url(https://static.miraheze.org/rainworldwiki/1/11/RW_sort_up.svg); background-repeat: no-repeat; background-position: right; padding-right: 21px; background-size: 21px; } .jquery-tablesorter th.headerSortDown { background-image: url(https://static.miraheze.org/rainworldwiki/9/94/RW_sort_down.svg); background-repeat: no-repeat; background-position: right; padding-right: 21px; background-size: 21px; } .updatedmarker { background-color: #474747; } .warningbox { background-color: #513c4900; border-color: #ffeafc; } .messagebox, .errorbox, .warningbox, .successbox { color: #ffeafd; } .cnotice { background-color: var(--bg-color-solid); } .cnotice-message p { color: var(--txt-color); } #cnotice-toggle-box a img { filter: invert(100%); } form#editcount table { background-color: #0000 !important; } /* languages footer */ .mw-pt-languages, .mw-pt-languages-label { background-color: var(--bg-color-solid); border-radius: 4px; } /* advanced search box */ .mw-search-profile-tabs { background-color: #f8f9fa00; } #mw-searchoptions { background-color: #f8f9fa00; } /* visual edit mode imageboxes */ figure[typeof~="mw:Image/Thumb"], figure[typeof~="mw:Video/Thumb"], figure[typeof~="mw:Audio/Thumb"], figure[typeof~="mw:Image/Frame"], figure[typeof~="mw:Video/Frame"], figure[typeof~="mw:Audio/Frame"] { background-color: var(--embed-bg); } figure[typeof~="mw:Image/Thumb"] > figcaption, figure[typeof~="mw:Video/Thumb"] > figcaption, figure[typeof~="mw:Audio/Thumb"] > figcaption, figure[typeof~="mw:Image/Frame"] > figcaption, figure[typeof~="mw:Video/Frame"] > figcaption, figure[typeof~="mw:Audio/Frame"] > figcaption { background-color: var(--embed-bg); } /* visual edit mode popup box */ .oo-ui-popupWidget-popup { background-color: #241a24; } .mw-rcfilters-ui-filterTagItemWidget .oo-ui-labelElement-label, .oo-ui-buttonElement-button .oo-ui-labelElement-label { color: #000; } /* wiki extension manager */ #managewiki .managewiki-submit-formfields { background: #130e13; } .oo-ui-tabSelectWidget-framed { background-color: #150E15; } .successbox { background-color: #391f39; border-color: #C8CCD1; } /* multimedia viewer */ .mw-mmv-post-image { color: #eee; background-color: #221520; } .mw-ui-button.mw-ui-progressive:not(:disabled) { background-color: #0000; color: #000 !important; border-color: #eee; } .mw-mmv-stripe-button.mw-mmv-description-page-button, .mw-mmv-stripe-button.mw-mmv-description-page-button:active, .mw-mmv-stripe-button.mw-mmv-description-page-button:visited { color: #fff; } .mw-mmv-image.error { background-color: #241a22; } .mw-mmv-image-metadata { border-top: 1px solid #eee; background-color: #170d17; } .mw-mmv-image-links a:visited, .mw-mmv-about-links a:visited, .mw-mmv-image-metadata a:visited { color: #c8a; } .mw-mmv-image-links a, .mw-mmv-about-links a, .mw-mmv-image-metadata a { color: #fab; } /* inline icon placer */ pre, code, .mw-code { background-color: #171017c4; color: #eee; border: 1px solid #eee; } /* mediawiki common css */ .mw-content-ltr.mw-highlight-lines pre, .mw-content-ltr.content .mw-highlight-lines pre { padding-left: 3.5em; box-shadow: inset 2.75em 0 0 #4a2c3f59; } .mw-highlight .linenos { color: #eee; } /* text colour */ .mw-highlight .nc { color: #5A9AFF; } .mw-highlight .c { color: #3dcaca; } .mw-highlight .nv { color: #6C69FF; } .mw-highlight .nf { color: #3C49FF; } .mw-highlight .mh { color: #fff; } .mw-highlight .kc { color: #10b710; font-weight: bold; } .mw-highlight .nd { color: #E10BFF; } .mw-highlight .kt { color: #FF347E; } .mw-highlight .nn { color: #5A9AFF; } /* wiki userpage */ #profile-top { border: none; } .user-section-heading { border: none; line-height: 0px; margin: 0 0 20px 0; } #profile-right { float: none; } #user-page-left { width: 100%; float: right; padding-top: 20px; } #user-page-right { float: right; width: 100%; padding-top: 20px; } #p-personal { background: linear-gradient(to left, #15101560, #15101500); padding-right: 5px; } #mw-panel { background: linear-gradient(to right, #15101550, #15101500); height: 100%; } /* links */ a.new { color: #dd3333 !important; } a[href^="/wiki/User:"], a[href^="/wiki/User:"]:visited { color: #9b59b6; font-style: italic; } /* js breadcrumbs */ .jsbc-breadcrumbs { background-color: #0000; border-color: #eee; } /* hiding ip */ a.mw-anonuserlink bdi { visibility: hidden; font-size: 0; letter-spacing: -0px; } a.mw-anonuserlink bdi:after { content: "Unregistered user"; visibility: visible; font-size: 14px; font-weight: bold; color: white; } /* upload file error */ .messagebox, .errorbox, .warningbox, .successbox { color: #fff; } .errorbox { background-color: #fd2e2e70; border-color: #f75252; } /* discord banners */ .discord-banner { width: 320px; height: 76px; background-image: url("https://discordapp.com/api/guilds/291184728944410624/embed.png?style=banner2"); } .discord-shield { width: 119px; height: 20px; background-image: url("https://discordapp.com/api/guilds/291184728944410624/embed.png?style=shield"); } /* cookies banner */ .mw-cookiewarning-container { background-color: rgb(34, 20, 29); } /* video embeds (youtube, etc.) */ .embedvideo-consent { background-color: #000; } .embedvideo-consent__overlay { color: #eee; } .embedvideowrap { border: var(--txt-color-dark) 1px solid; } /* toolbar notifs popup */ .oo-ui-popupWidget-popup { background-color: #EAECF0; } .oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button { background-color: #EAECF0; } /* page editor */ #wpTextbox1 { background-color: var(--bg-color); color: var(--txt-color); } .editOptions { background-color: var(--bg-color-solid); color: var(--txt-color-dark); } .editOptions .oo-ui-labelElement-label { color: var(--txt-color); } /* fundraising notice */ .cnotice { background: #FCFCFC00; border: 1px solid #eee; } .cnotice-message p { color: #eee; } /* sitewide notice */ #siteNotice td { background-color: var(--embed-bg) !important; border: var(--txt-color-dark) 1px solid !important; } /* frb fundraising notice */ .frb { display: none; background-color: #fff0 !important; } .frb-greeting { color: #eee !important; } .frb-translateme { float: right; font-size: 60%; color: #eee !important; margin-top: -20px !important; } .mw-ui-button { background-color: #0000; border: 1px solid #eee; border-radius: 7px; } .frb-message-icon { height: 3em !important; width: 0em !important; } .frb-message-inner { background-color: #FFF0 !important; border-left: 2px solid #eee !important; border-radius: 7px !important; } .mh-notice--warning { border-left-color: #8c8c8c; background: #fff; } /* custom theme end */ f97908bc29c17c43aaa8c2518fe9994fe347cfe0 335 334 2022-09-08T14:12:58Z Cashewww 2 css text/css /* CSS placed here will be applied to all skins */ /* custom theme start */ :root { --bg-color: #151015ea; --bg-color-solid: #151015; --txt-color: #eee; --txt-color-dark: #bbb; --url-color: #fab; --url-color-visited: #c8a; --light-border-color: #fff6; --dark-pink: #867; --dark-green: #676; --table-bg-header: #0009; --table-bg: #0005; --edit-url-color: #c9b; --toc-bg-color: #0002; --toc-num-color: #aaa; --leftnavbar-url-color: #fef; --leftnavbar-header-color: #ddd; --header-bg-color: #12101250; --header-tab-bg: linear-gradient(#302530da,#151015da); --header-tab-color: #eee; --embed-bg: #171017b0; --diff-delete: #955; --diff-add: #595; } /* main */ body { background-color: var(--bg-color-solid); background-image: url(https://static.miraheze.org/rainworldmoddingwiki/e/e4/LandscapeHI.png); background-position: center; background-repeat: no-repeat; background-attachment: fixed; background-size: cover; } .mw-body { background-color: var(--bg-color); color: var(--txt-color); border: 1px solid var(--light-border-color); } .mw-body h1, h2, h3, h4, h5, h6 { color: var(--txt-color); } .mw-body h1 { font-size: 2em !important; } .mw-body h2 { font-size: 1.6em !important; } .mw-body h3 { font-size: 1.4em !important; } .mw-body h4 { font-size: 1.2em !important; } .mw-body a, .mw-parser-output a.external { color: var(--url-color); } .mw-body a:visited, .mw-parser-output a.external:visited { color: var(--url-color-visited) } .mw-body .mw-editsection a { color: var(--edit-url-color); } ul { list-style: disc; } /* table of contents */ .toc { background-color: var(--toc-bg-color); border-radius: 4px; } .tocnumber { color: var(--toc-num-color); } .toctext { color: var(--leftnavbar-url-color) } /* left nav bar */ #mw-panel { background-color: var(--header-bg-color); } #mw-panel a { color: var(--leftnavbar-url-color); font-weight: 600; } #mw-panel span { color: var(--leftnavbar-header-color); } /* header */ #mw-page-base { background: none; } #mw-head { background-color: var(--header-bg-color); } #mw-head .vector-menu-content-list li { background-image: var(--header-tab-bg); } #mw-head a { color: var(--header-tab-color); } #mw-head #p-personal li { background-image: none; } .oo-ui-icon-tray, .oo-ui-icon-bell { background-color: var(--txt-color); } #mw-head #p-personal #pt-userpage a { color: var(--leftnavbar-url-color); } /* thumbnails and embeds */ .thumbinner, .catlinks { background-color: var(--embed-bg) !important; } .catlinks { border-radius: 4px; } .catlinks a { color: var(--leftnavbar-url-color) } .thumbimage { background-color: var(--embed-bg); } /* infoboxes */ .infoboxtable { float: right; padding: 10px; border: 1px solid var(--txt-color); border-radius: 4px; font-size: 90%; margin-left: 1em; margin-bottom: 0.5em; width: 300px } .infoboxtable td { vertical-align: top } .infoboxtable td > div { background-color: var(--embed-bg); font-weight: bold; padding: 0.5px 7px } .infoboxname { background-color: var(--embed-bg); font-size: 110%; font-weight: bold; padding: 0.4em } .infoboxdetails { background-color: var(--embed-bg); padding: 0.15em; } .infoboxname, .infoboxdetails, .infoboxtable .mw-collapsible th{ border-radius: 2px !important; border: 1px solid #767; } .mw-collapsible th { background-color: var(--embed-bg) !important; } /* file history */ #filetoc { background-color: var(--toc-bg-color); border: 1px solid var(--txt-color); border-radius: 2px; } /* footer */ #footer-info li { color: var(--leftnavbar-header-color); } #footer-info a, #footer-places a { color: var(--leftnavbar-url-color); font-weight: 800; } /* image gallery */ li.gallerybox div.thumb { background-color: var(--toc-bg-color); border-radius: 3px; } /* general tables */ .wikitable { background-color: var(--table-bg-color) !important; color: var(--txt-color) !important; } .wikitable th { background-color: var(--table-bg-header) !important; } /* page history comparer */ #pagehistory li.selected { background-color: transparent; outline: none; color: var(--txt-color); border: 1px dashed var(--txt-color); } /* page diff */ .diff-context { background-color: var(--embed-bg); color: var(--txt-color); } .diff-deletedline { border-color: var(--diff-delete); } .diff-deletedline .diffchange { background-color: var(--diff-delete); } .diff-addedline { border-color: var(--diff-add); } .diff-addedline .diffchange { background-color: var(--diff-add); } /* recent changes page */ .oo-ui-tagMultiselectWidget.oo-ui-widget-enabled.oo-ui-tagMultiselectWidget-outlined .oo-ui-tagItemWidget.oo-ui-widget-enabled, .mw-rcfilters-ui-filterTagMultiselectWidget.oo-ui-widget-enabled .oo-ui-tagMultiselectWidget-handle, .oo-ui-tagMultiselectWidget.oo-ui-widget-enabled.oo-ui-tagMultiselectWidget-outlined, .oo-ui-textInputWidget .oo-ui-inputWidget-input, .mw-rcfilters-ui-changesListWrapperWidget .mw-changeslist-legend { background-color: var(--embed-bg); border-radius: 3px; } .mw-rcfilters-ui-filterTagItemWidget .oo-ui-labelElement-label, .oo-ui-buttonElement-button .oo-ui-labelElement-label { color: var(--txt-color-dark); } .mw-rcfilters-ui-filterWrapperWidget-showNewChanges .oo-ui-labelElement-label, .mw-rcfilters-ui-filterTagMultiselectWidget .oo-ui-labelElement-label { color: var(--txt-color); } /* file metadata and licensing */ .toccolours { background-color: var(--embed-bg); } .fileinfo-paramfield { background-color: var(--bg-color-solid) } .licensetpl_wrapper, .licensetpl, .layouttemplate table { background-color: var(--embed-bg) !important; } #mw_metadata th, #mw_metadata td { background-color: var(--embed-bg); } /* uploaded files list */ .mw-datatable th, .mw-datatable td { background-color: var(--embed-bg); } .mw-datatable tr:hover td { background-color: var(--bg-color-solid); } /* search bar */ #searchInput { background-color: var(--embed-bg); border-color: var(--light-border-color); color: var(--txt-color); } /* deleted pages page text box & email text box */ .oo-ui-textInputWidget .oo-ui-inputWidget-input { color: var(--txt-color); } /* help text (extensions manager, etc.) */ .oo-ui-inline-help { color: var(--txt-color-dark) !important; } /* main page page creator */ .createboxInput { background-color: var(--embed-bg); border-color: var(--txt-color-dark); color: var(--txt-color) } .mw-ui-button.mw-ui-progressive, .mw-ui-button.mw-ui-progressive:disabled { background-color: var(--embed-bg); border: 1px solid var(--txt-color-dark); transition: ease-in-out 0.3s; } .mw-ui-button.mw-ui-progressive:hover, .mw-ui-button.mw-ui-progressive:disabled:hover { background-color: var(--embed-bg); border: 1px solid var(--url-color); } .mw-body-content blockquote { border-left: 2px solid #eaecf040; } /* userprofile extension support */ #profile-image img { background-color: transparent; border-radius: 4px; } .no-info-container, .profile-info-container, .profile-on { background-color: var(--embed-bg); border: 1px solid var(--txt-color); border-radius: 4px; color: var(--txt-color); } .profile-info-container { margin-bottom: 20px; } .profile-info-container div { padding: 10px 20px; color: var(--txt-color); } .profile-info-container div b { color: var(--txt-color-dark); font-size: 0.9em; } #profile-toggle-button, .profile-tab-on, .profile-tab { background-color: var(--embed-bg); border: 1px solid var(--txt-color-dark); border-radius: 3px; } .profile-tab-on { background-color: var(--dark-pink); } .profile-on { background-color: var(--dark-green); color: white; padding: 5px; } .profile-update-title, .profile-update-unit-left { color: var(--txt-color); } .eye-container { opacity: 0.8; } .eye-container .title { color: black; } .eye-container .menu .item, .eye-container .menu .item:hover { color: black; } .tux-editor-header { color: #fff; font-size: 14px; } .group-warning { background: #371425; padding: 5px; margin: 5px 0; } .tux-breadcrumb { color: #fff; font-size: 14pt; line-height: 1.25em; } .tux-breadcrumb__item--aggregate { cursor: pointer; color: #FEF; } .ext-translate-language-selector-label { color: #fff; } .ext-translate-language-selector .uls { color: #FEF; cursor: pointer; min-height: 1px; position: relative; } .toctogglelabel { cursor: pointer; color: #fff; } .jquery-tablesorter th.headerSort { background-image: url(https://static.miraheze.org/rainworldwiki/c/c3/RW_sort_both.svg); background-repeat: no-repeat; background-position: right; padding-right: 21px; background-size: 21px; } .jquery-tablesorter th.headerSortUp { background-image: url(https://static.miraheze.org/rainworldwiki/1/11/RW_sort_up.svg); background-repeat: no-repeat; background-position: right; padding-right: 21px; background-size: 21px; } .jquery-tablesorter th.headerSortDown { background-image: url(https://static.miraheze.org/rainworldwiki/9/94/RW_sort_down.svg); background-repeat: no-repeat; background-position: right; padding-right: 21px; background-size: 21px; } .updatedmarker { background-color: #474747; } .warningbox { background-color: #513c4900; border-color: #ffeafc; } .messagebox, .errorbox, .warningbox, .successbox { color: #ffeafd; } .cnotice { background-color: var(--bg-color-solid); } .cnotice-message p { color: var(--txt-color); } #cnotice-toggle-box a img { filter: invert(100%); } form#editcount table { background-color: #0000 !important; } /* languages footer */ .mw-pt-languages, .mw-pt-languages-label { background-color: var(--bg-color-solid); border-radius: 4px; } /* advanced search box */ .mw-search-profile-tabs { background-color: #f8f9fa00; } #mw-searchoptions { background-color: #f8f9fa00; } /* visual edit mode imageboxes */ figure[typeof~="mw:Image/Thumb"], figure[typeof~="mw:Video/Thumb"], figure[typeof~="mw:Audio/Thumb"], figure[typeof~="mw:Image/Frame"], figure[typeof~="mw:Video/Frame"], figure[typeof~="mw:Audio/Frame"] { background-color: var(--embed-bg); } figure[typeof~="mw:Image/Thumb"] > figcaption, figure[typeof~="mw:Video/Thumb"] > figcaption, figure[typeof~="mw:Audio/Thumb"] > figcaption, figure[typeof~="mw:Image/Frame"] > figcaption, figure[typeof~="mw:Video/Frame"] > figcaption, figure[typeof~="mw:Audio/Frame"] > figcaption { background-color: var(--embed-bg); } /* visual edit mode popup box */ .oo-ui-popupWidget-popup { background-color: #241a24; } .mw-rcfilters-ui-filterTagItemWidget .oo-ui-labelElement-label, .oo-ui-buttonElement-button .oo-ui-labelElement-label { color: #000; } /* wiki extension manager */ #managewiki .managewiki-submit-formfields { background: #130e13; } .oo-ui-tabSelectWidget-framed { background-color: #150E15; } .successbox { background-color: #391f39; border-color: #C8CCD1; } /* multimedia viewer */ .mw-mmv-post-image { color: #eee; background-color: #221520; } .mw-ui-button.mw-ui-progressive:not(:disabled) { background-color: #0000; color: #000 !important; border-color: #eee; } .mw-mmv-stripe-button.mw-mmv-description-page-button, .mw-mmv-stripe-button.mw-mmv-description-page-button:active, .mw-mmv-stripe-button.mw-mmv-description-page-button:visited { color: #fff; } .mw-mmv-image.error { background-color: #241a22; } .mw-mmv-image-metadata { border-top: 1px solid #eee; background-color: #170d17; } .mw-mmv-image-links a:visited, .mw-mmv-about-links a:visited, .mw-mmv-image-metadata a:visited { color: #c8a; } .mw-mmv-image-links a, .mw-mmv-about-links a, .mw-mmv-image-metadata a { color: #fab; } /* inline icon placer */ pre, code, .mw-code { background-color: #171017c4; color: #eee; border: 1px solid #eee; } /* mediawiki common css */ .mw-content-ltr.mw-highlight-lines pre, .mw-content-ltr.content .mw-highlight-lines pre { padding-left: 3.5em; box-shadow: inset 2.75em 0 0 #4a2c3f59; } .mw-highlight .linenos { color: #eee; } /* text colour */ .mw-highlight .nc { color: #5A9AFF; } .mw-highlight .c { color: #3dcaca; } .mw-highlight .nv { color: #6C69FF; } .mw-highlight .nf { color: #3C49FF; } .mw-highlight .mh { color: #fff; } .mw-highlight .kc { color: #10b710; font-weight: bold; } .mw-highlight .nd { color: #E10BFF; } .mw-highlight .kt { color: #FF347E; } .mw-highlight .nn { color: #5A9AFF; } /* wiki userpage */ #profile-top { border: none; } .user-section-heading { border: none; line-height: 0px; margin: 0 0 20px 0; } #profile-right { float: none; } #user-page-left { width: 100%; float: right; padding-top: 20px; } #user-page-right { float: right; width: 100%; padding-top: 20px; } #p-personal { background: linear-gradient(to left, #15101560, #15101500); padding-right: 5px; } #mw-panel { background: linear-gradient(to right, #15101550, #15101500); height: 100%; } /* links */ a.new { color: #dd3333 !important; } a[href^="/wiki/User:"], a[href^="/wiki/User:"]:visited { color: #9b59b6; font-style: italic; } /* js breadcrumbs */ .jsbc-breadcrumbs { background-color: #0000; border-color: #eee; } /* hiding ip */ a.mw-anonuserlink bdi { visibility: hidden; font-size: 0; letter-spacing: -0px; } a.mw-anonuserlink bdi:after { content: "Unregistered user"; visibility: visible; font-size: 14px; font-weight: bold; color: white; } /* upload file error */ .messagebox, .errorbox, .warningbox, .successbox { color: #fff; } .errorbox { background-color: #fd2e2e70; border-color: #f75252; } /* discord banners */ .discord-banner { width: 320px; height: 76px; background-image: url("https://discordapp.com/api/guilds/291184728944410624/embed.png?style=banner2"); } .discord-shield { width: 119px; height: 20px; background-image: url("https://discordapp.com/api/guilds/291184728944410624/embed.png?style=shield"); } /* cookies banner */ .mw-cookiewarning-container { background-color: rgb(34, 20, 29); } /* video embeds (youtube, etc.) */ .embedvideo-consent { background-color: #000; } .embedvideo-consent__overlay { color: #eee; } .embedvideowrap { border: var(--txt-color-dark) 1px solid; } /* toolbar notifs popup */ .oo-ui-popupWidget-popup { background-color: #EAECF0; } .oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button { background-color: #EAECF0; } /* page editor */ #wpTextbox1 { background-color: var(--bg-color); color: var(--txt-color); } .editOptions { background-color: var(--bg-color-solid); color: var(--txt-color-dark); } .editOptions .oo-ui-labelElement-label { color: var(--txt-color); } /* fundraising notice */ .cnotice { background: #FCFCFC00; border: 1px solid #eee; } .cnotice-message p { color: #eee; } /* sitewide notice */ #siteNotice td { background-color: var(--embed-bg) !important; border: var(--txt-color-dark) 1px solid !important; } /* frb fundraising notice */ .frb { display: none; background-color: #fff0 !important; } .frb-greeting { color: #eee !important; } .frb-translateme { float: right; font-size: 60%; color: #eee !important; margin-top: -20px !important; } .mw-ui-button { background-color: #0000; border: 1px solid #eee; border-radius: 7px; } .frb-message-icon { height: 3em !important; width: 0em !important; } .frb-message-inner { background-color: #FFF0 !important; border-left: 2px solid #eee !important; border-radius: 7px !important; } .mh-notice--warning { border-left-color: #8c8c8c; background: #fff; } /* custom theme end */ c230102302ad33205b044675597093c7240f6791 Region From The Ground Up 0 136 336 240 2022-09-11T01:36:56Z MACMAN2003 21 /* Dev tool configurations */ fixed dev tools link wikitext text/x-wiki {{Cleanup}} {{todo|target=page}} So you want to make a region, but you have no clue where to start! The idea of modding something so big is certainly daunting! However, looking at everything in small repeatable pieces will let you work step by step until one day you’ll suddenly have a finished region! However before that happens you need to learn some basics to get you started! Lets start with some terminology of the tools used! * [[Level Editor]] - This is the tool given to the modding community by the Rain World developers. These are the actual tools used to make Rain World. However much of its features and hotkeys are difficult and quirky to work with at first, but given enough time and use, the editor becomes an extremely powerful tool. * Unofficial level editor - This is a tool created by AndrewFM and Mikronaut to edit Rain World rooms before the official editor was released. While it lacks many features needed to make rooms. It does have the incredibly useful feature of being able to edit already exported rooms. As well as changing creature dens into doors, and vice versa. * [[Dev Tools]] - These are in game tools Rain World uses for editing room visual effects, sounds, and triggers. As well as the regions map, and the various other specific configurations of your room! * [[World File Format]] - This controls how your region (or any other region!) binds rooms together. As well as creature spawns! * Room settings text - These files are present for every room that you save a configuration for in the dev tools. It contains the placement of objects, sounds, room effects, and any other setting applied using the dev tools. I will not be giving a full control outline for every editor in this tutorial. If you need the editor’s controls, please see the full article on the specific tool you are using for their list of inputs and quirks. This article is an exercise in how to bring a level from an empty screen, to a fully fleshed out room. Largely following my own process. Don’t be afraid to branch out and try weirder things as you get comfortable with the editor! == Important terms and info == * A region is a large collection of connected rooms. Using a Worldfile to setup data inside them. * A room is stored as several files that contain: ** Geometry and pathfinding data ** Room graphics, one .PNG file per camera ** Settings file containing additional data such as room effects, sound triggers and placed objects (defined in [[Dev Tools]]) * The editor can only export the collision and graphics for rooms, Dev Tools are used to set the colors and effects. * Every room needs at least one valid door in order to be connected * By default, the editor will create a room the correct size for a single screen, with a single camera already set up. <!--This is why the guide assumes only a single screen to help you learn to use the editor.--> By default, a single room is 72 x 43. '''Changing room size after some tiles have been added breaks the tiles, and has a chance of corrupting the level project with uneraseable invisible tiles!''' == Setting Up == [[File:rfg-1.png|thumb|none|alt=1|1]] Once you open the official editor for the first time. you will be greeted with a file select. It is advised to make a folder for your rooms to keep them organized before you open the editor. Use the arrow keys to navigate into that folder, and press N to make a new room. You will then be greeted with the editor’s main menu. === Saving, and name quirks: === Before we do anything, lets save our room. It is REQUIRED that you start all of your rooms names with a region prefix. You can check the Rain World, World folder for the regions in game. We will be using SU_ the prefix for outskirts, at least until we have several rooms for our region later, or you are confident enough to begin making rooms for your own region. Secondly, NEVER use spaces. Always use an underscore _ to separate your name’s sections. Examples of correct room names: * SU_test01 * SU_myroom * SU_my_room * SU_another_room * SU_lotsandlotsofroom15 * SU_A04 The developers often used the letter (A, B, C…, J…) after the underscore _ to track the number of cameras in the room (for non-shelter (S) rooms), but this is not required. Examples of actual rooms in the game: * SU_A05 - small Outskirts room with 1 camera (A) * SU_B08 - larger Outskirts room with 2 cameras (B) * HI_C14 - wide Industrial Complex room with 3 cameras (C) * CC_D01 - tall Chimney Canopy room with 4 cameras (D) * SL_F01 - Shoreline room with 6 cameras (F) * UW_J01 - huge room in The Wall with 10 cameras (J) So now. You are ready to begin painting! == A Blank Canvas == [[File:rfg-2.png|thumb|none|alt=2|2]] Click the geometry editor button to begin painting your level’s basic geometry. However, before we do anything. We will first clear all the layer using the “clear all” tool. Use the arrow keys while the mouse is over the tile grid to change tools. Once the red box is over the X shaped tool. Used the numpad to navigate to the top left corner, click once to start drawing the rectangle of the clear tool, and navigate to the bottom right to place the other corner. When you are finished all the solid walls in the room will be removed. Leaving you with a completely blank canvas to work from. A “fuzzy” grey border marks the very edge of a room. Where tiles no longer exist to the game. The white rectangle is the game play border Anything outside of this will repeat off into the distance, this ONLY applies to the room’s collision. Visually they will be fine. All room in Rain World use these borders. For a more simple explanation. Keep everything related to gameplay inside the white rectangle! Anything outside will only show up visually, but will not act the same as they would inside the rectangle! == Blocking It Out == [[File:rfg-3.png|thumb|none|alt=3|3]] Lets start painting out the shapes we want for our basic level! This seems like a bit sudden of a jump, but only a few moments of messing around in the editor will let you achieve what you see in the screenshot! Short cuts to doors and dens require walls to be placed in specific ways around them. The [[level-editor/Geometry-Editor.html|Geometry Editor]] article goes into more depth about properly connecting short cuts, doors, and dens. For now, we will simply place walls, some poles, and at least one “Entrance” to the room. The Dens seen in the screenshot are optional. Only one door is required for this tutorial. == A Test Render == [[File:rfg-4.png|thumb|none|alt=4|4]] Before we move on; Lets do another save. So if anything goes wrong we won’t lose the level geometry we now have. Press 1 on the number row to return to the main menu, and press the save button! Press enter in the name field to save the room without changing the name of it. It is now time to do a test render of our room so we can see if it plays correctly in game! First, we need to click “Text Output” to save the levels collision data, and then press “Render Level.” The editor will appear to freeze for a few moments. This is normal! Do not be worried, or attempt to close the editor! Eventually the editor will begin processing each layer of the room. Before it will render the rooms data into a red and black image. The files will be output into the “Levels” folder by the editor’s executable. The files ROOMNAME.txt and ROOMNAME_1.png are the exported version of your room, for use by Rain Worlds engine. Lets get to seeing our room in game! == Our First Link == For now. We will be using outskirts as a quick way to test our room. We don’t have our own region yet after all! There is already an easy to use DISCONNECTED door in outskirts, close to the start of the game. Lets move our room files to where they are needed! First. Copy the ROOMNAME.txt and ROOMNAME_1.png files from the editor’s level export folder. Then navigate to “Rain World”. Inside you will see various other room files, and their settings file. For now, we will simply paste our room files into this folder. Second. We will go one folder up. So we are inside the “SU” region folder. In here you will see Outskirt’s World.txt file. The detail of this file are in this article: [[World-File-Format.html|World File Format]]. However, for the purpose of this tutorial, we will be following the next steps to install our room to Outskirts! Third. Open World_SU.txt. Inside we will see several door connections, creature spawns, and other region related data. Look for the line: * SU_A63 : SU_B12, SU_A37, DISCONNECTED This room has a disconnected door we can use to hook our room into easily! Lets add our room into the file! At the end of the end of the ROOMS section, but before the END ROOMS tag, add in our room’s name. Followed by a : Then add SU_A63. This will link our door to SU_A63. My room’s entry looks like this: * SU_myroom : SU_A63 We now need to make sure SU_A63 connects to our room as well! We simply need to change DISCONNECTED into our rooms name. Mine looks like: * SU_A63 : SU_B12, SU_A37, SU_myroom We can now start Rain World! If this has all been done correctly. Then you will be able to load your file without it crashing to a grey screen. Simply navigate to SU_A63 to see the freshly added connection! You can peak into SU’s “Rooms” folder, and find SU_A63_1.png to see what the room looks like to know where it is in game! == Making Mistakes == [[File:rfg-5.png|thumb|none|alt=5|5]] Our first room is pretty rough! Not everything will be perfect of course! This is a time to see if everything in our geometry works right! If pits are impossible to jump across, or if a jump is just a little our of reach. This is the time to tweak our level till we are happy with the layout. Render times are very fast with just a single layer and some walls after all! Don’t be afraid of mistakes at this point. Just fix them and tweak until your room feels like it is playable, and there are no locations that you can become stuck in. Repeat the steps above to edit, re-render, and re-install the room. You will no longer need to link the level to the world again! You only need to update the room files and image. You do not even need to close Rain World to test these changes. Simply dying, and returning to the room is enough to cause the room to reload for you to test the new collisions! == A Start To Detailing == [[File:rfg-6.png|thumb|none|alt=6|6]] This looks like another crazy jump! But once you get used to the materials the editor gives you, the tile editor will become a playground, and you may even start designing your levels with it, and instead use the geometry editor just to compliment your tiles! It will all come to you as your understanding and comfort of the editor increases. The details I’ve applied myself, have been to paint various materials in the same style Outskirts uses. Large metal plates surrounding dense pipes on corners. Concrete as the base material. The rare inclusion of pipes and machines. Along with a few things I enjoy using in my own levels. Such as large signs from the Misc category, and the insides of large pipes! The tile menu can be navigated using WASD keys. Many large tiles have a collision requirement. Holding G while clicking will automatically place the required geometry for you. This allows you to build things like pipes or complex machines without revisiting the geometry editor, or to construct rooms almost entirely out of tiles. However, you will still need to visit the geometry editor at some point for the bulk of your room’s padding. Where you will paint the traditional tile “materials” over solid walls. The colored dots in the picture are walls painted with a specific material. These are applied as the level is rendered! For now we are still just focusing on layer 1! == A Second Render == [[File:rfg-7.png|thumb|none|alt=7|7]] Things are starting to come together now! We can do a second little peak at how the room plays. After all, we’ve likely done some tweaks with our detailing. Something is still missing however. Using only the first layer of Rain World’s rooms can only give us so much detail! This level needs some DEPTH! == Depth, and the Art of Backgrounds == [[File:rfg-8.png|thumb|none|alt=8|8]] Lets head back into the editor! In the geometry editor, use the layer tool in the bottom left to change to layer 2, and paint over the places we want to place a “back wall” to our room! This layer is also one that creatures can climb on. Blue lizards often do this! Some details on the first layer will also “bleed” into layers behind them. This happens most with the insides of pipes and large chimneys! You can see in the screenshot that I have not placed any layer 2 walls behind the pipe segments at the bottom of the room’s vat area. I’ve done this so that the back wall will not cover over the inside of the pipes during the render! Once you are done painting, save, export text, and do a render! Lets do another test of how our level looks! == A Third Render == [[File:rfg-9.png|thumb|none|alt=9|9]] Yet another render, and more to see and tweak! We can fix any mistakes easily as we go. You can also skip each rendering step, and do all the layers at once if you are confident with the editor! I’ll be doing a third layer, and correcting all the issues on layer 2 by the next section. All the info you need is in the official editor’s article here: [[level-editor/Official-Level-Editor.html|Official Level Editor]]. There is also a large guide of all tiles and materials, and how they look once rendered here: https://imgur.com/a/Vz3Kk The next steps involve tweaking, rendering, retweaking, and rerendering until you are happy with the base design of your level! Remember, that some creatures use layer 2 to climb on walls, but layer 3 is far enough in the background for nothing to interact with it! Layer 1 is solid to all creatures with few if at all exceptions. Make sure you cannot get trapped in your level! == Effects and You == [[File:rfg-10.png|thumb|none|alt=10|10]] It’s time to start painting! Now that you’ve solved any issues on your tile layers, and painted yourself a background layer. You are now ready to start painting effects! Remember though. Each effect slows down the render of the level quite a bit. From now on it will begin to get more time consuming to fix mistakes in the level! Especially once you start making larger rooms! Effects are what make Rain World rooms look special. They alter, distort, and deform your tiles. Grow plants, and even alter tiles entirely! The effects editor has an example image of every effect, and its basic usage outline in this article: [[level-editor/Effect-Editor|Effects Editor]]. For the basics though! BlackGoo and Slime; These two effects are used in nearly every screen in Rain World to some degree! Slime makes every tile look slightly drippy and goopy. Like a mess has been rubbed onto them. BlackGoo forms the outer “shadow” of rooms. Both of these work together to make your room look less repetitive and clean! == Yet another rendering == [[File:rfg-11.png|thumb|none|alt=11|11]] Look how far we’ve come! From an empty screen with nothing. To a room that feels like it is simply missing “something” before it is finished! Things like the brickwork along the sides passing over the BlackGoo( It only applies itself over certain materials!) can be corrected using large junk or dirt where you would want the BlackGoo down there. You can also apply other effects till you are happy with the room. This includes everything from rubble, distortions, plants, and even daddy long leg corrupted walls! The only limits is your imagination to making effects work together, and the tiles you have to use! Once you’ve applied the effects you want, and have re-rendered till the level looks right. Next up is to add some props to our room! == Fancy Props and Design == [[File:rfg-12.png|thumb|none|alt=12|12]] Remember to always save and keep backups! Some editor tabs can be more fussy then others! Props are used to detail your room even further. Allowing you to place details without the grid, and at any angle and distorted shape you want! The control are outlined in the article here: [[level-editor/Prop-Editor.html|Prop Editor]]. While this is not too complex of a section. Adding a few proper can help break the rather straight geometry normally present in Rain World’s levels by giving them some more curved shapes to look at. Such as tubes and valves between containers or machines! Once you are all setup, we can render and move onto using the dev tools to configure the rooms more fine details! Remember. You can always re-render and re-export a level as many times as you need. At no point does a level become impossible to edit. With the one exception of losing its project save file! == Dev tool configurations == [[File:rfg-13.png|thumb|none|alt=13|13]] We can now move onto using the [[Dev Tools]] to configure the level’s more detailed settings! Everything from the room’s colors, effects, and even how the rain timer affects this room! Want a section of outskirts with some kind of lightning machine? Go ahead! Want to make a flooding cave system? It’s all in here! The room’s palette is not tied to the region. However most regions have “templates” that you can use to automatically set room settings to. Instead of needing to do each room one by one the same way. You can change anything you need to away from the template default, or click “NONE” beneath in the template section to use purely your own settings. The rooms palette can also be configured to fade between it, and another palette. Allowing you to configure the exact colors you would need. The various effects can also be configured to use Color1 or Color2 of the effect palettes. These are used to set the colors of plants. Giant signs, and even daddy long leg corruption! Exploring the dev tools documentation will give you far more info and ideas then me directly telling you every possible situation. Remember that some objects and room settings require a reload of the room to appear! Don’t forget to add sounds and some environmental ambience to flesh out your room, to make it feel like a unique location in this world! ''A very IMPORTANT notice! Be sure to click the save button before you reload the room'' somehow! Or your changes will be lost! All of these configurations are save to ROOMNAME_settings.txt. == Over and Over Again == [[File:rfg-14.png|thumb|none|alt=14|14]] The process of making a full region is filled with this! Making rooms from the ground up, detailing and configuring them, before linking another room onto the chain. The only real difference is that you are doing so from the gates of your own region, instead of a small room connected to the side of outskirts! There are already a few pages of documentation related to connecting in a new region yourself! The main one can be found here: [[Adding-A-New-Region.html|Adding new Regions]]. The details of how to setup creatures and connections for the region are here: [[World-File-Format.html|World File Format]]. Finally, the dev tool’s map editor for making your region properly show as a map in game is here: [[dev-tools/Map.html|Map Tab]]. I’ll likely be expanding this guide at some point in the future, but for now this is the basics of how to create a room from scratch! Look through the other articles for things like: Raising the water level, setting up creature spawns, understanding doors, adding food, placing objects and plants, adding sounds and effects, specific room triggers, and the various special room settings! And remember! Have fun! == Why Do My Rooms Crash? == There are multiple reasons Rain World will dislike your rooms or connections. These are a few common, and more niche reasons why the game may be crashing. === Doors outside of room bounds: === ALWAYS place every part of a short cut’s path inside the room’s boundary. Any short cut paths outside of it are ignored and will break the game when loaded. Crashing to a grey screen on file load. === Accidental Doors and Dens: === The editor is a strange tool. It also has a second cursor in geometry mode… for some reason. An accidental key press may have placed a den, short cut entrance, or other kind of door in the room without proper connections. Take a peak over your room for any issues. === Incorrect Region Prefix: === the prefix at the start of a room file should match the region you are placing it inside. For this guide we focus on tests rooms inside of outskirts ( SU_ ). If you are bringing these rooms to a custom region by renaming them, be sure to open the room’s data file, and edit the first line to match the renamed version of the file. [[Category:Content Mods]] dfbe4a3136aff876a9563fed2868986d372a4403 337 336 2022-09-11T01:40:57Z MACMAN2003 21 /* Over and Over Again */ fixed 2 out of the 3 links wikitext text/x-wiki {{Cleanup}} {{todo|target=page}} So you want to make a region, but you have no clue where to start! The idea of modding something so big is certainly daunting! However, looking at everything in small repeatable pieces will let you work step by step until one day you’ll suddenly have a finished region! However before that happens you need to learn some basics to get you started! Lets start with some terminology of the tools used! * [[Level Editor]] - This is the tool given to the modding community by the Rain World developers. These are the actual tools used to make Rain World. However much of its features and hotkeys are difficult and quirky to work with at first, but given enough time and use, the editor becomes an extremely powerful tool. * Unofficial level editor - This is a tool created by AndrewFM and Mikronaut to edit Rain World rooms before the official editor was released. While it lacks many features needed to make rooms. It does have the incredibly useful feature of being able to edit already exported rooms. As well as changing creature dens into doors, and vice versa. * [[Dev Tools]] - These are in game tools Rain World uses for editing room visual effects, sounds, and triggers. As well as the regions map, and the various other specific configurations of your room! * [[World File Format]] - This controls how your region (or any other region!) binds rooms together. As well as creature spawns! * Room settings text - These files are present for every room that you save a configuration for in the dev tools. It contains the placement of objects, sounds, room effects, and any other setting applied using the dev tools. I will not be giving a full control outline for every editor in this tutorial. If you need the editor’s controls, please see the full article on the specific tool you are using for their list of inputs and quirks. This article is an exercise in how to bring a level from an empty screen, to a fully fleshed out room. Largely following my own process. Don’t be afraid to branch out and try weirder things as you get comfortable with the editor! == Important terms and info == * A region is a large collection of connected rooms. Using a Worldfile to setup data inside them. * A room is stored as several files that contain: ** Geometry and pathfinding data ** Room graphics, one .PNG file per camera ** Settings file containing additional data such as room effects, sound triggers and placed objects (defined in [[Dev Tools]]) * The editor can only export the collision and graphics for rooms, Dev Tools are used to set the colors and effects. * Every room needs at least one valid door in order to be connected * By default, the editor will create a room the correct size for a single screen, with a single camera already set up. <!--This is why the guide assumes only a single screen to help you learn to use the editor.--> By default, a single room is 72 x 43. '''Changing room size after some tiles have been added breaks the tiles, and has a chance of corrupting the level project with uneraseable invisible tiles!''' == Setting Up == [[File:rfg-1.png|thumb|none|alt=1|1]] Once you open the official editor for the first time. you will be greeted with a file select. It is advised to make a folder for your rooms to keep them organized before you open the editor. Use the arrow keys to navigate into that folder, and press N to make a new room. You will then be greeted with the editor’s main menu. === Saving, and name quirks: === Before we do anything, lets save our room. It is REQUIRED that you start all of your rooms names with a region prefix. You can check the Rain World, World folder for the regions in game. We will be using SU_ the prefix for outskirts, at least until we have several rooms for our region later, or you are confident enough to begin making rooms for your own region. Secondly, NEVER use spaces. Always use an underscore _ to separate your name’s sections. Examples of correct room names: * SU_test01 * SU_myroom * SU_my_room * SU_another_room * SU_lotsandlotsofroom15 * SU_A04 The developers often used the letter (A, B, C…, J…) after the underscore _ to track the number of cameras in the room (for non-shelter (S) rooms), but this is not required. Examples of actual rooms in the game: * SU_A05 - small Outskirts room with 1 camera (A) * SU_B08 - larger Outskirts room with 2 cameras (B) * HI_C14 - wide Industrial Complex room with 3 cameras (C) * CC_D01 - tall Chimney Canopy room with 4 cameras (D) * SL_F01 - Shoreline room with 6 cameras (F) * UW_J01 - huge room in The Wall with 10 cameras (J) So now. You are ready to begin painting! == A Blank Canvas == [[File:rfg-2.png|thumb|none|alt=2|2]] Click the geometry editor button to begin painting your level’s basic geometry. However, before we do anything. We will first clear all the layer using the “clear all” tool. Use the arrow keys while the mouse is over the tile grid to change tools. Once the red box is over the X shaped tool. Used the numpad to navigate to the top left corner, click once to start drawing the rectangle of the clear tool, and navigate to the bottom right to place the other corner. When you are finished all the solid walls in the room will be removed. Leaving you with a completely blank canvas to work from. A “fuzzy” grey border marks the very edge of a room. Where tiles no longer exist to the game. The white rectangle is the game play border Anything outside of this will repeat off into the distance, this ONLY applies to the room’s collision. Visually they will be fine. All room in Rain World use these borders. For a more simple explanation. Keep everything related to gameplay inside the white rectangle! Anything outside will only show up visually, but will not act the same as they would inside the rectangle! == Blocking It Out == [[File:rfg-3.png|thumb|none|alt=3|3]] Lets start painting out the shapes we want for our basic level! This seems like a bit sudden of a jump, but only a few moments of messing around in the editor will let you achieve what you see in the screenshot! Short cuts to doors and dens require walls to be placed in specific ways around them. The [[level-editor/Geometry-Editor.html|Geometry Editor]] article goes into more depth about properly connecting short cuts, doors, and dens. For now, we will simply place walls, some poles, and at least one “Entrance” to the room. The Dens seen in the screenshot are optional. Only one door is required for this tutorial. == A Test Render == [[File:rfg-4.png|thumb|none|alt=4|4]] Before we move on; Lets do another save. So if anything goes wrong we won’t lose the level geometry we now have. Press 1 on the number row to return to the main menu, and press the save button! Press enter in the name field to save the room without changing the name of it. It is now time to do a test render of our room so we can see if it plays correctly in game! First, we need to click “Text Output” to save the levels collision data, and then press “Render Level.” The editor will appear to freeze for a few moments. This is normal! Do not be worried, or attempt to close the editor! Eventually the editor will begin processing each layer of the room. Before it will render the rooms data into a red and black image. The files will be output into the “Levels” folder by the editor’s executable. The files ROOMNAME.txt and ROOMNAME_1.png are the exported version of your room, for use by Rain Worlds engine. Lets get to seeing our room in game! == Our First Link == For now. We will be using outskirts as a quick way to test our room. We don’t have our own region yet after all! There is already an easy to use DISCONNECTED door in outskirts, close to the start of the game. Lets move our room files to where they are needed! First. Copy the ROOMNAME.txt and ROOMNAME_1.png files from the editor’s level export folder. Then navigate to “Rain World”. Inside you will see various other room files, and their settings file. For now, we will simply paste our room files into this folder. Second. We will go one folder up. So we are inside the “SU” region folder. In here you will see Outskirt’s World.txt file. The detail of this file are in this article: [[World-File-Format.html|World File Format]]. However, for the purpose of this tutorial, we will be following the next steps to install our room to Outskirts! Third. Open World_SU.txt. Inside we will see several door connections, creature spawns, and other region related data. Look for the line: * SU_A63 : SU_B12, SU_A37, DISCONNECTED This room has a disconnected door we can use to hook our room into easily! Lets add our room into the file! At the end of the end of the ROOMS section, but before the END ROOMS tag, add in our room’s name. Followed by a : Then add SU_A63. This will link our door to SU_A63. My room’s entry looks like this: * SU_myroom : SU_A63 We now need to make sure SU_A63 connects to our room as well! We simply need to change DISCONNECTED into our rooms name. Mine looks like: * SU_A63 : SU_B12, SU_A37, SU_myroom We can now start Rain World! If this has all been done correctly. Then you will be able to load your file without it crashing to a grey screen. Simply navigate to SU_A63 to see the freshly added connection! You can peak into SU’s “Rooms” folder, and find SU_A63_1.png to see what the room looks like to know where it is in game! == Making Mistakes == [[File:rfg-5.png|thumb|none|alt=5|5]] Our first room is pretty rough! Not everything will be perfect of course! This is a time to see if everything in our geometry works right! If pits are impossible to jump across, or if a jump is just a little our of reach. This is the time to tweak our level till we are happy with the layout. Render times are very fast with just a single layer and some walls after all! Don’t be afraid of mistakes at this point. Just fix them and tweak until your room feels like it is playable, and there are no locations that you can become stuck in. Repeat the steps above to edit, re-render, and re-install the room. You will no longer need to link the level to the world again! You only need to update the room files and image. You do not even need to close Rain World to test these changes. Simply dying, and returning to the room is enough to cause the room to reload for you to test the new collisions! == A Start To Detailing == [[File:rfg-6.png|thumb|none|alt=6|6]] This looks like another crazy jump! But once you get used to the materials the editor gives you, the tile editor will become a playground, and you may even start designing your levels with it, and instead use the geometry editor just to compliment your tiles! It will all come to you as your understanding and comfort of the editor increases. The details I’ve applied myself, have been to paint various materials in the same style Outskirts uses. Large metal plates surrounding dense pipes on corners. Concrete as the base material. The rare inclusion of pipes and machines. Along with a few things I enjoy using in my own levels. Such as large signs from the Misc category, and the insides of large pipes! The tile menu can be navigated using WASD keys. Many large tiles have a collision requirement. Holding G while clicking will automatically place the required geometry for you. This allows you to build things like pipes or complex machines without revisiting the geometry editor, or to construct rooms almost entirely out of tiles. However, you will still need to visit the geometry editor at some point for the bulk of your room’s padding. Where you will paint the traditional tile “materials” over solid walls. The colored dots in the picture are walls painted with a specific material. These are applied as the level is rendered! For now we are still just focusing on layer 1! == A Second Render == [[File:rfg-7.png|thumb|none|alt=7|7]] Things are starting to come together now! We can do a second little peak at how the room plays. After all, we’ve likely done some tweaks with our detailing. Something is still missing however. Using only the first layer of Rain World’s rooms can only give us so much detail! This level needs some DEPTH! == Depth, and the Art of Backgrounds == [[File:rfg-8.png|thumb|none|alt=8|8]] Lets head back into the editor! In the geometry editor, use the layer tool in the bottom left to change to layer 2, and paint over the places we want to place a “back wall” to our room! This layer is also one that creatures can climb on. Blue lizards often do this! Some details on the first layer will also “bleed” into layers behind them. This happens most with the insides of pipes and large chimneys! You can see in the screenshot that I have not placed any layer 2 walls behind the pipe segments at the bottom of the room’s vat area. I’ve done this so that the back wall will not cover over the inside of the pipes during the render! Once you are done painting, save, export text, and do a render! Lets do another test of how our level looks! == A Third Render == [[File:rfg-9.png|thumb|none|alt=9|9]] Yet another render, and more to see and tweak! We can fix any mistakes easily as we go. You can also skip each rendering step, and do all the layers at once if you are confident with the editor! I’ll be doing a third layer, and correcting all the issues on layer 2 by the next section. All the info you need is in the official editor’s article here: [[level-editor/Official-Level-Editor.html|Official Level Editor]]. There is also a large guide of all tiles and materials, and how they look once rendered here: https://imgur.com/a/Vz3Kk The next steps involve tweaking, rendering, retweaking, and rerendering until you are happy with the base design of your level! Remember, that some creatures use layer 2 to climb on walls, but layer 3 is far enough in the background for nothing to interact with it! Layer 1 is solid to all creatures with few if at all exceptions. Make sure you cannot get trapped in your level! == Effects and You == [[File:rfg-10.png|thumb|none|alt=10|10]] It’s time to start painting! Now that you’ve solved any issues on your tile layers, and painted yourself a background layer. You are now ready to start painting effects! Remember though. Each effect slows down the render of the level quite a bit. From now on it will begin to get more time consuming to fix mistakes in the level! Especially once you start making larger rooms! Effects are what make Rain World rooms look special. They alter, distort, and deform your tiles. Grow plants, and even alter tiles entirely! The effects editor has an example image of every effect, and its basic usage outline in this article: [[level-editor/Effect-Editor|Effects Editor]]. For the basics though! BlackGoo and Slime; These two effects are used in nearly every screen in Rain World to some degree! Slime makes every tile look slightly drippy and goopy. Like a mess has been rubbed onto them. BlackGoo forms the outer “shadow” of rooms. Both of these work together to make your room look less repetitive and clean! == Yet another rendering == [[File:rfg-11.png|thumb|none|alt=11|11]] Look how far we’ve come! From an empty screen with nothing. To a room that feels like it is simply missing “something” before it is finished! Things like the brickwork along the sides passing over the BlackGoo( It only applies itself over certain materials!) can be corrected using large junk or dirt where you would want the BlackGoo down there. You can also apply other effects till you are happy with the room. This includes everything from rubble, distortions, plants, and even daddy long leg corrupted walls! The only limits is your imagination to making effects work together, and the tiles you have to use! Once you’ve applied the effects you want, and have re-rendered till the level looks right. Next up is to add some props to our room! == Fancy Props and Design == [[File:rfg-12.png|thumb|none|alt=12|12]] Remember to always save and keep backups! Some editor tabs can be more fussy then others! Props are used to detail your room even further. Allowing you to place details without the grid, and at any angle and distorted shape you want! The control are outlined in the article here: [[level-editor/Prop-Editor.html|Prop Editor]]. While this is not too complex of a section. Adding a few proper can help break the rather straight geometry normally present in Rain World’s levels by giving them some more curved shapes to look at. Such as tubes and valves between containers or machines! Once you are all setup, we can render and move onto using the dev tools to configure the rooms more fine details! Remember. You can always re-render and re-export a level as many times as you need. At no point does a level become impossible to edit. With the one exception of losing its project save file! == Dev tool configurations == [[File:rfg-13.png|thumb|none|alt=13|13]] We can now move onto using the [[Dev Tools]] to configure the level’s more detailed settings! Everything from the room’s colors, effects, and even how the rain timer affects this room! Want a section of outskirts with some kind of lightning machine? Go ahead! Want to make a flooding cave system? It’s all in here! The room’s palette is not tied to the region. However most regions have “templates” that you can use to automatically set room settings to. Instead of needing to do each room one by one the same way. You can change anything you need to away from the template default, or click “NONE” beneath in the template section to use purely your own settings. The rooms palette can also be configured to fade between it, and another palette. Allowing you to configure the exact colors you would need. The various effects can also be configured to use Color1 or Color2 of the effect palettes. These are used to set the colors of plants. Giant signs, and even daddy long leg corruption! Exploring the dev tools documentation will give you far more info and ideas then me directly telling you every possible situation. Remember that some objects and room settings require a reload of the room to appear! Don’t forget to add sounds and some environmental ambience to flesh out your room, to make it feel like a unique location in this world! ''A very IMPORTANT notice! Be sure to click the save button before you reload the room'' somehow! Or your changes will be lost! All of these configurations are save to ROOMNAME_settings.txt. == Over and Over Again == [[File:rfg-14.png|thumb|none|alt=14|14]] The process of making a full region is filled with this! Making rooms from the ground up, detailing and configuring them, before linking another room onto the chain. The only real difference is that you are doing so from the gates of your own region, instead of a small room connected to the side of outskirts! There are already a few pages of documentation related to connecting in a new region yourself! The main one can be found here: [[Adding-A-New-Region.html|Adding new Regions]]. The details of how to setup creatures and connections for the region are here: [[World File Format]]. Finally, the dev tool’s map editor for making your region properly show as a map in game is here: [[Dev_Tools#Interface_Tabs#Map-0|Map Tab]]. I’ll likely be expanding this guide at some point in the future, but for now this is the basics of how to create a room from scratch! Look through the other articles for things like: Raising the water level, setting up creature spawns, understanding doors, adding food, placing objects and plants, adding sounds and effects, specific room triggers, and the various special room settings! And remember! Have fun! == Why Do My Rooms Crash? == There are multiple reasons Rain World will dislike your rooms or connections. These are a few common, and more niche reasons why the game may be crashing. === Doors outside of room bounds: === ALWAYS place every part of a short cut’s path inside the room’s boundary. Any short cut paths outside of it are ignored and will break the game when loaded. Crashing to a grey screen on file load. === Accidental Doors and Dens: === The editor is a strange tool. It also has a second cursor in geometry mode… for some reason. An accidental key press may have placed a den, short cut entrance, or other kind of door in the room without proper connections. Take a peak over your room for any issues. === Incorrect Region Prefix: === the prefix at the start of a room file should match the region you are placing it inside. For this guide we focus on tests rooms inside of outskirts ( SU_ ). If you are bringing these rooms to a custom region by renaming them, be sure to open the room’s data file, and edit the first line to match the renamed version of the file. [[Category:Content Mods]] b9044e5296ca645a558eb5eaa8acd93fbe97f682 338 337 2022-09-11T01:43:23Z MACMAN2003 21 /* Blocking It Out */ fixed broken link wikitext text/x-wiki {{Cleanup}} {{todo|target=page}} So you want to make a region, but you have no clue where to start! The idea of modding something so big is certainly daunting! However, looking at everything in small repeatable pieces will let you work step by step until one day you’ll suddenly have a finished region! However before that happens you need to learn some basics to get you started! Lets start with some terminology of the tools used! * [[Level Editor]] - This is the tool given to the modding community by the Rain World developers. These are the actual tools used to make Rain World. However much of its features and hotkeys are difficult and quirky to work with at first, but given enough time and use, the editor becomes an extremely powerful tool. * Unofficial level editor - This is a tool created by AndrewFM and Mikronaut to edit Rain World rooms before the official editor was released. While it lacks many features needed to make rooms. It does have the incredibly useful feature of being able to edit already exported rooms. As well as changing creature dens into doors, and vice versa. * [[Dev Tools]] - These are in game tools Rain World uses for editing room visual effects, sounds, and triggers. As well as the regions map, and the various other specific configurations of your room! * [[World File Format]] - This controls how your region (or any other region!) binds rooms together. As well as creature spawns! * Room settings text - These files are present for every room that you save a configuration for in the dev tools. It contains the placement of objects, sounds, room effects, and any other setting applied using the dev tools. I will not be giving a full control outline for every editor in this tutorial. If you need the editor’s controls, please see the full article on the specific tool you are using for their list of inputs and quirks. This article is an exercise in how to bring a level from an empty screen, to a fully fleshed out room. Largely following my own process. Don’t be afraid to branch out and try weirder things as you get comfortable with the editor! == Important terms and info == * A region is a large collection of connected rooms. Using a Worldfile to setup data inside them. * A room is stored as several files that contain: ** Geometry and pathfinding data ** Room graphics, one .PNG file per camera ** Settings file containing additional data such as room effects, sound triggers and placed objects (defined in [[Dev Tools]]) * The editor can only export the collision and graphics for rooms, Dev Tools are used to set the colors and effects. * Every room needs at least one valid door in order to be connected * By default, the editor will create a room the correct size for a single screen, with a single camera already set up. <!--This is why the guide assumes only a single screen to help you learn to use the editor.--> By default, a single room is 72 x 43. '''Changing room size after some tiles have been added breaks the tiles, and has a chance of corrupting the level project with uneraseable invisible tiles!''' == Setting Up == [[File:rfg-1.png|thumb|none|alt=1|1]] Once you open the official editor for the first time. you will be greeted with a file select. It is advised to make a folder for your rooms to keep them organized before you open the editor. Use the arrow keys to navigate into that folder, and press N to make a new room. You will then be greeted with the editor’s main menu. === Saving, and name quirks: === Before we do anything, lets save our room. It is REQUIRED that you start all of your rooms names with a region prefix. You can check the Rain World, World folder for the regions in game. We will be using SU_ the prefix for outskirts, at least until we have several rooms for our region later, or you are confident enough to begin making rooms for your own region. Secondly, NEVER use spaces. Always use an underscore _ to separate your name’s sections. Examples of correct room names: * SU_test01 * SU_myroom * SU_my_room * SU_another_room * SU_lotsandlotsofroom15 * SU_A04 The developers often used the letter (A, B, C…, J…) after the underscore _ to track the number of cameras in the room (for non-shelter (S) rooms), but this is not required. Examples of actual rooms in the game: * SU_A05 - small Outskirts room with 1 camera (A) * SU_B08 - larger Outskirts room with 2 cameras (B) * HI_C14 - wide Industrial Complex room with 3 cameras (C) * CC_D01 - tall Chimney Canopy room with 4 cameras (D) * SL_F01 - Shoreline room with 6 cameras (F) * UW_J01 - huge room in The Wall with 10 cameras (J) So now. You are ready to begin painting! == A Blank Canvas == [[File:rfg-2.png|thumb|none|alt=2|2]] Click the geometry editor button to begin painting your level’s basic geometry. However, before we do anything. We will first clear all the layer using the “clear all” tool. Use the arrow keys while the mouse is over the tile grid to change tools. Once the red box is over the X shaped tool. Used the numpad to navigate to the top left corner, click once to start drawing the rectangle of the clear tool, and navigate to the bottom right to place the other corner. When you are finished all the solid walls in the room will be removed. Leaving you with a completely blank canvas to work from. A “fuzzy” grey border marks the very edge of a room. Where tiles no longer exist to the game. The white rectangle is the game play border Anything outside of this will repeat off into the distance, this ONLY applies to the room’s collision. Visually they will be fine. All room in Rain World use these borders. For a more simple explanation. Keep everything related to gameplay inside the white rectangle! Anything outside will only show up visually, but will not act the same as they would inside the rectangle! == Blocking It Out == [[File:rfg-3.png|thumb|none|alt=3|3]] Lets start painting out the shapes we want for our basic level! This seems like a bit sudden of a jump, but only a few moments of messing around in the editor will let you achieve what you see in the screenshot! Short cuts to doors and dens require walls to be placed in specific ways around them. The [[Level Editor#Editors|Geometry Editor]] article goes into more depth about properly connecting short cuts, doors, and dens. For now, we will simply place walls, some poles, and at least one “Entrance” to the room. The Dens seen in the screenshot are optional. Only one door is required for this tutorial. == A Test Render == [[File:rfg-4.png|thumb|none|alt=4|4]] Before we move on; Lets do another save. So if anything goes wrong we won’t lose the level geometry we now have. Press 1 on the number row to return to the main menu, and press the save button! Press enter in the name field to save the room without changing the name of it. It is now time to do a test render of our room so we can see if it plays correctly in game! First, we need to click “Text Output” to save the levels collision data, and then press “Render Level.” The editor will appear to freeze for a few moments. This is normal! Do not be worried, or attempt to close the editor! Eventually the editor will begin processing each layer of the room. Before it will render the rooms data into a red and black image. The files will be output into the “Levels” folder by the editor’s executable. The files ROOMNAME.txt and ROOMNAME_1.png are the exported version of your room, for use by Rain Worlds engine. Lets get to seeing our room in game! == Our First Link == For now. We will be using outskirts as a quick way to test our room. We don’t have our own region yet after all! There is already an easy to use DISCONNECTED door in outskirts, close to the start of the game. Lets move our room files to where they are needed! First. Copy the ROOMNAME.txt and ROOMNAME_1.png files from the editor’s level export folder. Then navigate to “Rain World”. Inside you will see various other room files, and their settings file. For now, we will simply paste our room files into this folder. Second. We will go one folder up. So we are inside the “SU” region folder. In here you will see Outskirt’s World.txt file. The detail of this file are in this article: [[World-File-Format.html|World File Format]]. However, for the purpose of this tutorial, we will be following the next steps to install our room to Outskirts! Third. Open World_SU.txt. Inside we will see several door connections, creature spawns, and other region related data. Look for the line: * SU_A63 : SU_B12, SU_A37, DISCONNECTED This room has a disconnected door we can use to hook our room into easily! Lets add our room into the file! At the end of the end of the ROOMS section, but before the END ROOMS tag, add in our room’s name. Followed by a : Then add SU_A63. This will link our door to SU_A63. My room’s entry looks like this: * SU_myroom : SU_A63 We now need to make sure SU_A63 connects to our room as well! We simply need to change DISCONNECTED into our rooms name. Mine looks like: * SU_A63 : SU_B12, SU_A37, SU_myroom We can now start Rain World! If this has all been done correctly. Then you will be able to load your file without it crashing to a grey screen. Simply navigate to SU_A63 to see the freshly added connection! You can peak into SU’s “Rooms” folder, and find SU_A63_1.png to see what the room looks like to know where it is in game! == Making Mistakes == [[File:rfg-5.png|thumb|none|alt=5|5]] Our first room is pretty rough! Not everything will be perfect of course! This is a time to see if everything in our geometry works right! If pits are impossible to jump across, or if a jump is just a little our of reach. This is the time to tweak our level till we are happy with the layout. Render times are very fast with just a single layer and some walls after all! Don’t be afraid of mistakes at this point. Just fix them and tweak until your room feels like it is playable, and there are no locations that you can become stuck in. Repeat the steps above to edit, re-render, and re-install the room. You will no longer need to link the level to the world again! You only need to update the room files and image. You do not even need to close Rain World to test these changes. Simply dying, and returning to the room is enough to cause the room to reload for you to test the new collisions! == A Start To Detailing == [[File:rfg-6.png|thumb|none|alt=6|6]] This looks like another crazy jump! But once you get used to the materials the editor gives you, the tile editor will become a playground, and you may even start designing your levels with it, and instead use the geometry editor just to compliment your tiles! It will all come to you as your understanding and comfort of the editor increases. The details I’ve applied myself, have been to paint various materials in the same style Outskirts uses. Large metal plates surrounding dense pipes on corners. Concrete as the base material. The rare inclusion of pipes and machines. Along with a few things I enjoy using in my own levels. Such as large signs from the Misc category, and the insides of large pipes! The tile menu can be navigated using WASD keys. Many large tiles have a collision requirement. Holding G while clicking will automatically place the required geometry for you. This allows you to build things like pipes or complex machines without revisiting the geometry editor, or to construct rooms almost entirely out of tiles. However, you will still need to visit the geometry editor at some point for the bulk of your room’s padding. Where you will paint the traditional tile “materials” over solid walls. The colored dots in the picture are walls painted with a specific material. These are applied as the level is rendered! For now we are still just focusing on layer 1! == A Second Render == [[File:rfg-7.png|thumb|none|alt=7|7]] Things are starting to come together now! We can do a second little peak at how the room plays. After all, we’ve likely done some tweaks with our detailing. Something is still missing however. Using only the first layer of Rain World’s rooms can only give us so much detail! This level needs some DEPTH! == Depth, and the Art of Backgrounds == [[File:rfg-8.png|thumb|none|alt=8|8]] Lets head back into the editor! In the geometry editor, use the layer tool in the bottom left to change to layer 2, and paint over the places we want to place a “back wall” to our room! This layer is also one that creatures can climb on. Blue lizards often do this! Some details on the first layer will also “bleed” into layers behind them. This happens most with the insides of pipes and large chimneys! You can see in the screenshot that I have not placed any layer 2 walls behind the pipe segments at the bottom of the room’s vat area. I’ve done this so that the back wall will not cover over the inside of the pipes during the render! Once you are done painting, save, export text, and do a render! Lets do another test of how our level looks! == A Third Render == [[File:rfg-9.png|thumb|none|alt=9|9]] Yet another render, and more to see and tweak! We can fix any mistakes easily as we go. You can also skip each rendering step, and do all the layers at once if you are confident with the editor! I’ll be doing a third layer, and correcting all the issues on layer 2 by the next section. All the info you need is in the official editor’s article here: [[level-editor/Official-Level-Editor.html|Official Level Editor]]. There is also a large guide of all tiles and materials, and how they look once rendered here: https://imgur.com/a/Vz3Kk The next steps involve tweaking, rendering, retweaking, and rerendering until you are happy with the base design of your level! Remember, that some creatures use layer 2 to climb on walls, but layer 3 is far enough in the background for nothing to interact with it! Layer 1 is solid to all creatures with few if at all exceptions. Make sure you cannot get trapped in your level! == Effects and You == [[File:rfg-10.png|thumb|none|alt=10|10]] It’s time to start painting! Now that you’ve solved any issues on your tile layers, and painted yourself a background layer. You are now ready to start painting effects! Remember though. Each effect slows down the render of the level quite a bit. From now on it will begin to get more time consuming to fix mistakes in the level! Especially once you start making larger rooms! Effects are what make Rain World rooms look special. They alter, distort, and deform your tiles. Grow plants, and even alter tiles entirely! The effects editor has an example image of every effect, and its basic usage outline in this article: [[level-editor/Effect-Editor|Effects Editor]]. For the basics though! BlackGoo and Slime; These two effects are used in nearly every screen in Rain World to some degree! Slime makes every tile look slightly drippy and goopy. Like a mess has been rubbed onto them. BlackGoo forms the outer “shadow” of rooms. Both of these work together to make your room look less repetitive and clean! == Yet another rendering == [[File:rfg-11.png|thumb|none|alt=11|11]] Look how far we’ve come! From an empty screen with nothing. To a room that feels like it is simply missing “something” before it is finished! Things like the brickwork along the sides passing over the BlackGoo( It only applies itself over certain materials!) can be corrected using large junk or dirt where you would want the BlackGoo down there. You can also apply other effects till you are happy with the room. This includes everything from rubble, distortions, plants, and even daddy long leg corrupted walls! The only limits is your imagination to making effects work together, and the tiles you have to use! Once you’ve applied the effects you want, and have re-rendered till the level looks right. Next up is to add some props to our room! == Fancy Props and Design == [[File:rfg-12.png|thumb|none|alt=12|12]] Remember to always save and keep backups! Some editor tabs can be more fussy then others! Props are used to detail your room even further. Allowing you to place details without the grid, and at any angle and distorted shape you want! The control are outlined in the article here: [[level-editor/Prop-Editor.html|Prop Editor]]. While this is not too complex of a section. Adding a few proper can help break the rather straight geometry normally present in Rain World’s levels by giving them some more curved shapes to look at. Such as tubes and valves between containers or machines! Once you are all setup, we can render and move onto using the dev tools to configure the rooms more fine details! Remember. You can always re-render and re-export a level as many times as you need. At no point does a level become impossible to edit. With the one exception of losing its project save file! == Dev tool configurations == [[File:rfg-13.png|thumb|none|alt=13|13]] We can now move onto using the [[Dev Tools]] to configure the level’s more detailed settings! Everything from the room’s colors, effects, and even how the rain timer affects this room! Want a section of outskirts with some kind of lightning machine? Go ahead! Want to make a flooding cave system? It’s all in here! The room’s palette is not tied to the region. However most regions have “templates” that you can use to automatically set room settings to. Instead of needing to do each room one by one the same way. You can change anything you need to away from the template default, or click “NONE” beneath in the template section to use purely your own settings. The rooms palette can also be configured to fade between it, and another palette. Allowing you to configure the exact colors you would need. The various effects can also be configured to use Color1 or Color2 of the effect palettes. These are used to set the colors of plants. Giant signs, and even daddy long leg corruption! Exploring the dev tools documentation will give you far more info and ideas then me directly telling you every possible situation. Remember that some objects and room settings require a reload of the room to appear! Don’t forget to add sounds and some environmental ambience to flesh out your room, to make it feel like a unique location in this world! ''A very IMPORTANT notice! Be sure to click the save button before you reload the room'' somehow! Or your changes will be lost! All of these configurations are save to ROOMNAME_settings.txt. == Over and Over Again == [[File:rfg-14.png|thumb|none|alt=14|14]] The process of making a full region is filled with this! Making rooms from the ground up, detailing and configuring them, before linking another room onto the chain. The only real difference is that you are doing so from the gates of your own region, instead of a small room connected to the side of outskirts! There are already a few pages of documentation related to connecting in a new region yourself! The main one can be found here: [[Adding-A-New-Region.html|Adding new Regions]]. The details of how to setup creatures and connections for the region are here: [[World File Format]]. Finally, the dev tool’s map editor for making your region properly show as a map in game is here: [[Dev_Tools#Interface_Tabs#Map-0|Map Tab]]. I’ll likely be expanding this guide at some point in the future, but for now this is the basics of how to create a room from scratch! Look through the other articles for things like: Raising the water level, setting up creature spawns, understanding doors, adding food, placing objects and plants, adding sounds and effects, specific room triggers, and the various special room settings! And remember! Have fun! == Why Do My Rooms Crash? == There are multiple reasons Rain World will dislike your rooms or connections. These are a few common, and more niche reasons why the game may be crashing. === Doors outside of room bounds: === ALWAYS place every part of a short cut’s path inside the room’s boundary. Any short cut paths outside of it are ignored and will break the game when loaded. Crashing to a grey screen on file load. === Accidental Doors and Dens: === The editor is a strange tool. It also has a second cursor in geometry mode… for some reason. An accidental key press may have placed a den, short cut entrance, or other kind of door in the room without proper connections. Take a peak over your room for any issues. === Incorrect Region Prefix: === the prefix at the start of a room file should match the region you are placing it inside. For this guide we focus on tests rooms inside of outskirts ( SU_ ). If you are bringing these rooms to a custom region by renaming them, be sure to open the room’s data file, and edit the first line to match the renamed version of the file. [[Category:Content Mods]] a8c8647515d7203c13261fb6384597de2688993a 339 338 2022-09-11T01:44:02Z MACMAN2003 21 /* Our First Link */ fixed broken link wikitext text/x-wiki {{Cleanup}} {{todo|target=page}} So you want to make a region, but you have no clue where to start! The idea of modding something so big is certainly daunting! However, looking at everything in small repeatable pieces will let you work step by step until one day you’ll suddenly have a finished region! However before that happens you need to learn some basics to get you started! Lets start with some terminology of the tools used! * [[Level Editor]] - This is the tool given to the modding community by the Rain World developers. These are the actual tools used to make Rain World. However much of its features and hotkeys are difficult and quirky to work with at first, but given enough time and use, the editor becomes an extremely powerful tool. * Unofficial level editor - This is a tool created by AndrewFM and Mikronaut to edit Rain World rooms before the official editor was released. While it lacks many features needed to make rooms. It does have the incredibly useful feature of being able to edit already exported rooms. As well as changing creature dens into doors, and vice versa. * [[Dev Tools]] - These are in game tools Rain World uses for editing room visual effects, sounds, and triggers. As well as the regions map, and the various other specific configurations of your room! * [[World File Format]] - This controls how your region (or any other region!) binds rooms together. As well as creature spawns! * Room settings text - These files are present for every room that you save a configuration for in the dev tools. It contains the placement of objects, sounds, room effects, and any other setting applied using the dev tools. I will not be giving a full control outline for every editor in this tutorial. If you need the editor’s controls, please see the full article on the specific tool you are using for their list of inputs and quirks. This article is an exercise in how to bring a level from an empty screen, to a fully fleshed out room. Largely following my own process. Don’t be afraid to branch out and try weirder things as you get comfortable with the editor! == Important terms and info == * A region is a large collection of connected rooms. Using a Worldfile to setup data inside them. * A room is stored as several files that contain: ** Geometry and pathfinding data ** Room graphics, one .PNG file per camera ** Settings file containing additional data such as room effects, sound triggers and placed objects (defined in [[Dev Tools]]) * The editor can only export the collision and graphics for rooms, Dev Tools are used to set the colors and effects. * Every room needs at least one valid door in order to be connected * By default, the editor will create a room the correct size for a single screen, with a single camera already set up. <!--This is why the guide assumes only a single screen to help you learn to use the editor.--> By default, a single room is 72 x 43. '''Changing room size after some tiles have been added breaks the tiles, and has a chance of corrupting the level project with uneraseable invisible tiles!''' == Setting Up == [[File:rfg-1.png|thumb|none|alt=1|1]] Once you open the official editor for the first time. you will be greeted with a file select. It is advised to make a folder for your rooms to keep them organized before you open the editor. Use the arrow keys to navigate into that folder, and press N to make a new room. You will then be greeted with the editor’s main menu. === Saving, and name quirks: === Before we do anything, lets save our room. It is REQUIRED that you start all of your rooms names with a region prefix. You can check the Rain World, World folder for the regions in game. We will be using SU_ the prefix for outskirts, at least until we have several rooms for our region later, or you are confident enough to begin making rooms for your own region. Secondly, NEVER use spaces. Always use an underscore _ to separate your name’s sections. Examples of correct room names: * SU_test01 * SU_myroom * SU_my_room * SU_another_room * SU_lotsandlotsofroom15 * SU_A04 The developers often used the letter (A, B, C…, J…) after the underscore _ to track the number of cameras in the room (for non-shelter (S) rooms), but this is not required. Examples of actual rooms in the game: * SU_A05 - small Outskirts room with 1 camera (A) * SU_B08 - larger Outskirts room with 2 cameras (B) * HI_C14 - wide Industrial Complex room with 3 cameras (C) * CC_D01 - tall Chimney Canopy room with 4 cameras (D) * SL_F01 - Shoreline room with 6 cameras (F) * UW_J01 - huge room in The Wall with 10 cameras (J) So now. You are ready to begin painting! == A Blank Canvas == [[File:rfg-2.png|thumb|none|alt=2|2]] Click the geometry editor button to begin painting your level’s basic geometry. However, before we do anything. We will first clear all the layer using the “clear all” tool. Use the arrow keys while the mouse is over the tile grid to change tools. Once the red box is over the X shaped tool. Used the numpad to navigate to the top left corner, click once to start drawing the rectangle of the clear tool, and navigate to the bottom right to place the other corner. When you are finished all the solid walls in the room will be removed. Leaving you with a completely blank canvas to work from. A “fuzzy” grey border marks the very edge of a room. Where tiles no longer exist to the game. The white rectangle is the game play border Anything outside of this will repeat off into the distance, this ONLY applies to the room’s collision. Visually they will be fine. All room in Rain World use these borders. For a more simple explanation. Keep everything related to gameplay inside the white rectangle! Anything outside will only show up visually, but will not act the same as they would inside the rectangle! == Blocking It Out == [[File:rfg-3.png|thumb|none|alt=3|3]] Lets start painting out the shapes we want for our basic level! This seems like a bit sudden of a jump, but only a few moments of messing around in the editor will let you achieve what you see in the screenshot! Short cuts to doors and dens require walls to be placed in specific ways around them. The [[Level Editor#Editors|Geometry Editor]] article goes into more depth about properly connecting short cuts, doors, and dens. For now, we will simply place walls, some poles, and at least one “Entrance” to the room. The Dens seen in the screenshot are optional. Only one door is required for this tutorial. == A Test Render == [[File:rfg-4.png|thumb|none|alt=4|4]] Before we move on; Lets do another save. So if anything goes wrong we won’t lose the level geometry we now have. Press 1 on the number row to return to the main menu, and press the save button! Press enter in the name field to save the room without changing the name of it. It is now time to do a test render of our room so we can see if it plays correctly in game! First, we need to click “Text Output” to save the levels collision data, and then press “Render Level.” The editor will appear to freeze for a few moments. This is normal! Do not be worried, or attempt to close the editor! Eventually the editor will begin processing each layer of the room. Before it will render the rooms data into a red and black image. The files will be output into the “Levels” folder by the editor’s executable. The files ROOMNAME.txt and ROOMNAME_1.png are the exported version of your room, for use by Rain Worlds engine. Lets get to seeing our room in game! == Our First Link == For now. We will be using outskirts as a quick way to test our room. We don’t have our own region yet after all! There is already an easy to use DISCONNECTED door in outskirts, close to the start of the game. Lets move our room files to where they are needed! First. Copy the ROOMNAME.txt and ROOMNAME_1.png files from the editor’s level export folder. Then navigate to “Rain World”. Inside you will see various other room files, and their settings file. For now, we will simply paste our room files into this folder. Second. We will go one folder up. So we are inside the “SU” region folder. In here you will see Outskirt’s World.txt file. The detail of this file are in this article: [[World File Format]]. However, for the purpose of this tutorial, we will be following the next steps to install our room to Outskirts! Third. Open World_SU.txt. Inside we will see several door connections, creature spawns, and other region related data. Look for the line: * SU_A63 : SU_B12, SU_A37, DISCONNECTED This room has a disconnected door we can use to hook our room into easily! Lets add our room into the file! At the end of the end of the ROOMS section, but before the END ROOMS tag, add in our room’s name. Followed by a : Then add SU_A63. This will link our door to SU_A63. My room’s entry looks like this: * SU_myroom : SU_A63 We now need to make sure SU_A63 connects to our room as well! We simply need to change DISCONNECTED into our rooms name. Mine looks like: * SU_A63 : SU_B12, SU_A37, SU_myroom We can now start Rain World! If this has all been done correctly. Then you will be able to load your file without it crashing to a grey screen. Simply navigate to SU_A63 to see the freshly added connection! You can peak into SU’s “Rooms” folder, and find SU_A63_1.png to see what the room looks like to know where it is in game! == Making Mistakes == [[File:rfg-5.png|thumb|none|alt=5|5]] Our first room is pretty rough! Not everything will be perfect of course! This is a time to see if everything in our geometry works right! If pits are impossible to jump across, or if a jump is just a little our of reach. This is the time to tweak our level till we are happy with the layout. Render times are very fast with just a single layer and some walls after all! Don’t be afraid of mistakes at this point. Just fix them and tweak until your room feels like it is playable, and there are no locations that you can become stuck in. Repeat the steps above to edit, re-render, and re-install the room. You will no longer need to link the level to the world again! You only need to update the room files and image. You do not even need to close Rain World to test these changes. Simply dying, and returning to the room is enough to cause the room to reload for you to test the new collisions! == A Start To Detailing == [[File:rfg-6.png|thumb|none|alt=6|6]] This looks like another crazy jump! But once you get used to the materials the editor gives you, the tile editor will become a playground, and you may even start designing your levels with it, and instead use the geometry editor just to compliment your tiles! It will all come to you as your understanding and comfort of the editor increases. The details I’ve applied myself, have been to paint various materials in the same style Outskirts uses. Large metal plates surrounding dense pipes on corners. Concrete as the base material. The rare inclusion of pipes and machines. Along with a few things I enjoy using in my own levels. Such as large signs from the Misc category, and the insides of large pipes! The tile menu can be navigated using WASD keys. Many large tiles have a collision requirement. Holding G while clicking will automatically place the required geometry for you. This allows you to build things like pipes or complex machines without revisiting the geometry editor, or to construct rooms almost entirely out of tiles. However, you will still need to visit the geometry editor at some point for the bulk of your room’s padding. Where you will paint the traditional tile “materials” over solid walls. The colored dots in the picture are walls painted with a specific material. These are applied as the level is rendered! For now we are still just focusing on layer 1! == A Second Render == [[File:rfg-7.png|thumb|none|alt=7|7]] Things are starting to come together now! We can do a second little peak at how the room plays. After all, we’ve likely done some tweaks with our detailing. Something is still missing however. Using only the first layer of Rain World’s rooms can only give us so much detail! This level needs some DEPTH! == Depth, and the Art of Backgrounds == [[File:rfg-8.png|thumb|none|alt=8|8]] Lets head back into the editor! In the geometry editor, use the layer tool in the bottom left to change to layer 2, and paint over the places we want to place a “back wall” to our room! This layer is also one that creatures can climb on. Blue lizards often do this! Some details on the first layer will also “bleed” into layers behind them. This happens most with the insides of pipes and large chimneys! You can see in the screenshot that I have not placed any layer 2 walls behind the pipe segments at the bottom of the room’s vat area. I’ve done this so that the back wall will not cover over the inside of the pipes during the render! Once you are done painting, save, export text, and do a render! Lets do another test of how our level looks! == A Third Render == [[File:rfg-9.png|thumb|none|alt=9|9]] Yet another render, and more to see and tweak! We can fix any mistakes easily as we go. You can also skip each rendering step, and do all the layers at once if you are confident with the editor! I’ll be doing a third layer, and correcting all the issues on layer 2 by the next section. All the info you need is in the official editor’s article here: [[level-editor/Official-Level-Editor.html|Official Level Editor]]. There is also a large guide of all tiles and materials, and how they look once rendered here: https://imgur.com/a/Vz3Kk The next steps involve tweaking, rendering, retweaking, and rerendering until you are happy with the base design of your level! Remember, that some creatures use layer 2 to climb on walls, but layer 3 is far enough in the background for nothing to interact with it! Layer 1 is solid to all creatures with few if at all exceptions. Make sure you cannot get trapped in your level! == Effects and You == [[File:rfg-10.png|thumb|none|alt=10|10]] It’s time to start painting! Now that you’ve solved any issues on your tile layers, and painted yourself a background layer. You are now ready to start painting effects! Remember though. Each effect slows down the render of the level quite a bit. From now on it will begin to get more time consuming to fix mistakes in the level! Especially once you start making larger rooms! Effects are what make Rain World rooms look special. They alter, distort, and deform your tiles. Grow plants, and even alter tiles entirely! The effects editor has an example image of every effect, and its basic usage outline in this article: [[level-editor/Effect-Editor|Effects Editor]]. For the basics though! BlackGoo and Slime; These two effects are used in nearly every screen in Rain World to some degree! Slime makes every tile look slightly drippy and goopy. Like a mess has been rubbed onto them. BlackGoo forms the outer “shadow” of rooms. Both of these work together to make your room look less repetitive and clean! == Yet another rendering == [[File:rfg-11.png|thumb|none|alt=11|11]] Look how far we’ve come! From an empty screen with nothing. To a room that feels like it is simply missing “something” before it is finished! Things like the brickwork along the sides passing over the BlackGoo( It only applies itself over certain materials!) can be corrected using large junk or dirt where you would want the BlackGoo down there. You can also apply other effects till you are happy with the room. This includes everything from rubble, distortions, plants, and even daddy long leg corrupted walls! The only limits is your imagination to making effects work together, and the tiles you have to use! Once you’ve applied the effects you want, and have re-rendered till the level looks right. Next up is to add some props to our room! == Fancy Props and Design == [[File:rfg-12.png|thumb|none|alt=12|12]] Remember to always save and keep backups! Some editor tabs can be more fussy then others! Props are used to detail your room even further. Allowing you to place details without the grid, and at any angle and distorted shape you want! The control are outlined in the article here: [[level-editor/Prop-Editor.html|Prop Editor]]. While this is not too complex of a section. Adding a few proper can help break the rather straight geometry normally present in Rain World’s levels by giving them some more curved shapes to look at. Such as tubes and valves between containers or machines! Once you are all setup, we can render and move onto using the dev tools to configure the rooms more fine details! Remember. You can always re-render and re-export a level as many times as you need. At no point does a level become impossible to edit. With the one exception of losing its project save file! == Dev tool configurations == [[File:rfg-13.png|thumb|none|alt=13|13]] We can now move onto using the [[Dev Tools]] to configure the level’s more detailed settings! Everything from the room’s colors, effects, and even how the rain timer affects this room! Want a section of outskirts with some kind of lightning machine? Go ahead! Want to make a flooding cave system? It’s all in here! The room’s palette is not tied to the region. However most regions have “templates” that you can use to automatically set room settings to. Instead of needing to do each room one by one the same way. You can change anything you need to away from the template default, or click “NONE” beneath in the template section to use purely your own settings. The rooms palette can also be configured to fade between it, and another palette. Allowing you to configure the exact colors you would need. The various effects can also be configured to use Color1 or Color2 of the effect palettes. These are used to set the colors of plants. Giant signs, and even daddy long leg corruption! Exploring the dev tools documentation will give you far more info and ideas then me directly telling you every possible situation. Remember that some objects and room settings require a reload of the room to appear! Don’t forget to add sounds and some environmental ambience to flesh out your room, to make it feel like a unique location in this world! ''A very IMPORTANT notice! Be sure to click the save button before you reload the room'' somehow! Or your changes will be lost! All of these configurations are save to ROOMNAME_settings.txt. == Over and Over Again == [[File:rfg-14.png|thumb|none|alt=14|14]] The process of making a full region is filled with this! Making rooms from the ground up, detailing and configuring them, before linking another room onto the chain. The only real difference is that you are doing so from the gates of your own region, instead of a small room connected to the side of outskirts! There are already a few pages of documentation related to connecting in a new region yourself! The main one can be found here: [[Adding-A-New-Region.html|Adding new Regions]]. The details of how to setup creatures and connections for the region are here: [[World File Format]]. Finally, the dev tool’s map editor for making your region properly show as a map in game is here: [[Dev_Tools#Interface_Tabs#Map-0|Map Tab]]. I’ll likely be expanding this guide at some point in the future, but for now this is the basics of how to create a room from scratch! Look through the other articles for things like: Raising the water level, setting up creature spawns, understanding doors, adding food, placing objects and plants, adding sounds and effects, specific room triggers, and the various special room settings! And remember! Have fun! == Why Do My Rooms Crash? == There are multiple reasons Rain World will dislike your rooms or connections. These are a few common, and more niche reasons why the game may be crashing. === Doors outside of room bounds: === ALWAYS place every part of a short cut’s path inside the room’s boundary. Any short cut paths outside of it are ignored and will break the game when loaded. Crashing to a grey screen on file load. === Accidental Doors and Dens: === The editor is a strange tool. It also has a second cursor in geometry mode… for some reason. An accidental key press may have placed a den, short cut entrance, or other kind of door in the room without proper connections. Take a peak over your room for any issues. === Incorrect Region Prefix: === the prefix at the start of a room file should match the region you are placing it inside. For this guide we focus on tests rooms inside of outskirts ( SU_ ). If you are bringing these rooms to a custom region by renaming them, be sure to open the room’s data file, and edit the first line to match the renamed version of the file. [[Category:Content Mods]] 0834fb8692a261fbcf24938443c8d767e56cb4de 340 339 2022-09-11T01:47:59Z MACMAN2003 21 /* A Third Render */ Fixed broken link wikitext text/x-wiki {{Cleanup}} {{todo|target=page}} So you want to make a region, but you have no clue where to start! The idea of modding something so big is certainly daunting! However, looking at everything in small repeatable pieces will let you work step by step until one day you’ll suddenly have a finished region! However before that happens you need to learn some basics to get you started! Lets start with some terminology of the tools used! * [[Level Editor]] - This is the tool given to the modding community by the Rain World developers. These are the actual tools used to make Rain World. However much of its features and hotkeys are difficult and quirky to work with at first, but given enough time and use, the editor becomes an extremely powerful tool. * Unofficial level editor - This is a tool created by AndrewFM and Mikronaut to edit Rain World rooms before the official editor was released. While it lacks many features needed to make rooms. It does have the incredibly useful feature of being able to edit already exported rooms. As well as changing creature dens into doors, and vice versa. * [[Dev Tools]] - These are in game tools Rain World uses for editing room visual effects, sounds, and triggers. As well as the regions map, and the various other specific configurations of your room! * [[World File Format]] - This controls how your region (or any other region!) binds rooms together. As well as creature spawns! * Room settings text - These files are present for every room that you save a configuration for in the dev tools. It contains the placement of objects, sounds, room effects, and any other setting applied using the dev tools. I will not be giving a full control outline for every editor in this tutorial. If you need the editor’s controls, please see the full article on the specific tool you are using for their list of inputs and quirks. This article is an exercise in how to bring a level from an empty screen, to a fully fleshed out room. Largely following my own process. Don’t be afraid to branch out and try weirder things as you get comfortable with the editor! == Important terms and info == * A region is a large collection of connected rooms. Using a Worldfile to setup data inside them. * A room is stored as several files that contain: ** Geometry and pathfinding data ** Room graphics, one .PNG file per camera ** Settings file containing additional data such as room effects, sound triggers and placed objects (defined in [[Dev Tools]]) * The editor can only export the collision and graphics for rooms, Dev Tools are used to set the colors and effects. * Every room needs at least one valid door in order to be connected * By default, the editor will create a room the correct size for a single screen, with a single camera already set up. <!--This is why the guide assumes only a single screen to help you learn to use the editor.--> By default, a single room is 72 x 43. '''Changing room size after some tiles have been added breaks the tiles, and has a chance of corrupting the level project with uneraseable invisible tiles!''' == Setting Up == [[File:rfg-1.png|thumb|none|alt=1|1]] Once you open the official editor for the first time. you will be greeted with a file select. It is advised to make a folder for your rooms to keep them organized before you open the editor. Use the arrow keys to navigate into that folder, and press N to make a new room. You will then be greeted with the editor’s main menu. === Saving, and name quirks: === Before we do anything, lets save our room. It is REQUIRED that you start all of your rooms names with a region prefix. You can check the Rain World, World folder for the regions in game. We will be using SU_ the prefix for outskirts, at least until we have several rooms for our region later, or you are confident enough to begin making rooms for your own region. Secondly, NEVER use spaces. Always use an underscore _ to separate your name’s sections. Examples of correct room names: * SU_test01 * SU_myroom * SU_my_room * SU_another_room * SU_lotsandlotsofroom15 * SU_A04 The developers often used the letter (A, B, C…, J…) after the underscore _ to track the number of cameras in the room (for non-shelter (S) rooms), but this is not required. Examples of actual rooms in the game: * SU_A05 - small Outskirts room with 1 camera (A) * SU_B08 - larger Outskirts room with 2 cameras (B) * HI_C14 - wide Industrial Complex room with 3 cameras (C) * CC_D01 - tall Chimney Canopy room with 4 cameras (D) * SL_F01 - Shoreline room with 6 cameras (F) * UW_J01 - huge room in The Wall with 10 cameras (J) So now. You are ready to begin painting! == A Blank Canvas == [[File:rfg-2.png|thumb|none|alt=2|2]] Click the geometry editor button to begin painting your level’s basic geometry. However, before we do anything. We will first clear all the layer using the “clear all” tool. Use the arrow keys while the mouse is over the tile grid to change tools. Once the red box is over the X shaped tool. Used the numpad to navigate to the top left corner, click once to start drawing the rectangle of the clear tool, and navigate to the bottom right to place the other corner. When you are finished all the solid walls in the room will be removed. Leaving you with a completely blank canvas to work from. A “fuzzy” grey border marks the very edge of a room. Where tiles no longer exist to the game. The white rectangle is the game play border Anything outside of this will repeat off into the distance, this ONLY applies to the room’s collision. Visually they will be fine. All room in Rain World use these borders. For a more simple explanation. Keep everything related to gameplay inside the white rectangle! Anything outside will only show up visually, but will not act the same as they would inside the rectangle! == Blocking It Out == [[File:rfg-3.png|thumb|none|alt=3|3]] Lets start painting out the shapes we want for our basic level! This seems like a bit sudden of a jump, but only a few moments of messing around in the editor will let you achieve what you see in the screenshot! Short cuts to doors and dens require walls to be placed in specific ways around them. The [[Level Editor#Editors|Geometry Editor]] article goes into more depth about properly connecting short cuts, doors, and dens. For now, we will simply place walls, some poles, and at least one “Entrance” to the room. The Dens seen in the screenshot are optional. Only one door is required for this tutorial. == A Test Render == [[File:rfg-4.png|thumb|none|alt=4|4]] Before we move on; Lets do another save. So if anything goes wrong we won’t lose the level geometry we now have. Press 1 on the number row to return to the main menu, and press the save button! Press enter in the name field to save the room without changing the name of it. It is now time to do a test render of our room so we can see if it plays correctly in game! First, we need to click “Text Output” to save the levels collision data, and then press “Render Level.” The editor will appear to freeze for a few moments. This is normal! Do not be worried, or attempt to close the editor! Eventually the editor will begin processing each layer of the room. Before it will render the rooms data into a red and black image. The files will be output into the “Levels” folder by the editor’s executable. The files ROOMNAME.txt and ROOMNAME_1.png are the exported version of your room, for use by Rain Worlds engine. Lets get to seeing our room in game! == Our First Link == For now. We will be using outskirts as a quick way to test our room. We don’t have our own region yet after all! There is already an easy to use DISCONNECTED door in outskirts, close to the start of the game. Lets move our room files to where they are needed! First. Copy the ROOMNAME.txt and ROOMNAME_1.png files from the editor’s level export folder. Then navigate to “Rain World”. Inside you will see various other room files, and their settings file. For now, we will simply paste our room files into this folder. Second. We will go one folder up. So we are inside the “SU” region folder. In here you will see Outskirt’s World.txt file. The detail of this file are in this article: [[World File Format]]. However, for the purpose of this tutorial, we will be following the next steps to install our room to Outskirts! Third. Open World_SU.txt. Inside we will see several door connections, creature spawns, and other region related data. Look for the line: * SU_A63 : SU_B12, SU_A37, DISCONNECTED This room has a disconnected door we can use to hook our room into easily! Lets add our room into the file! At the end of the end of the ROOMS section, but before the END ROOMS tag, add in our room’s name. Followed by a : Then add SU_A63. This will link our door to SU_A63. My room’s entry looks like this: * SU_myroom : SU_A63 We now need to make sure SU_A63 connects to our room as well! We simply need to change DISCONNECTED into our rooms name. Mine looks like: * SU_A63 : SU_B12, SU_A37, SU_myroom We can now start Rain World! If this has all been done correctly. Then you will be able to load your file without it crashing to a grey screen. Simply navigate to SU_A63 to see the freshly added connection! You can peak into SU’s “Rooms” folder, and find SU_A63_1.png to see what the room looks like to know where it is in game! == Making Mistakes == [[File:rfg-5.png|thumb|none|alt=5|5]] Our first room is pretty rough! Not everything will be perfect of course! This is a time to see if everything in our geometry works right! If pits are impossible to jump across, or if a jump is just a little our of reach. This is the time to tweak our level till we are happy with the layout. Render times are very fast with just a single layer and some walls after all! Don’t be afraid of mistakes at this point. Just fix them and tweak until your room feels like it is playable, and there are no locations that you can become stuck in. Repeat the steps above to edit, re-render, and re-install the room. You will no longer need to link the level to the world again! You only need to update the room files and image. You do not even need to close Rain World to test these changes. Simply dying, and returning to the room is enough to cause the room to reload for you to test the new collisions! == A Start To Detailing == [[File:rfg-6.png|thumb|none|alt=6|6]] This looks like another crazy jump! But once you get used to the materials the editor gives you, the tile editor will become a playground, and you may even start designing your levels with it, and instead use the geometry editor just to compliment your tiles! It will all come to you as your understanding and comfort of the editor increases. The details I’ve applied myself, have been to paint various materials in the same style Outskirts uses. Large metal plates surrounding dense pipes on corners. Concrete as the base material. The rare inclusion of pipes and machines. Along with a few things I enjoy using in my own levels. Such as large signs from the Misc category, and the insides of large pipes! The tile menu can be navigated using WASD keys. Many large tiles have a collision requirement. Holding G while clicking will automatically place the required geometry for you. This allows you to build things like pipes or complex machines without revisiting the geometry editor, or to construct rooms almost entirely out of tiles. However, you will still need to visit the geometry editor at some point for the bulk of your room’s padding. Where you will paint the traditional tile “materials” over solid walls. The colored dots in the picture are walls painted with a specific material. These are applied as the level is rendered! For now we are still just focusing on layer 1! == A Second Render == [[File:rfg-7.png|thumb|none|alt=7|7]] Things are starting to come together now! We can do a second little peak at how the room plays. After all, we’ve likely done some tweaks with our detailing. Something is still missing however. Using only the first layer of Rain World’s rooms can only give us so much detail! This level needs some DEPTH! == Depth, and the Art of Backgrounds == [[File:rfg-8.png|thumb|none|alt=8|8]] Lets head back into the editor! In the geometry editor, use the layer tool in the bottom left to change to layer 2, and paint over the places we want to place a “back wall” to our room! This layer is also one that creatures can climb on. Blue lizards often do this! Some details on the first layer will also “bleed” into layers behind them. This happens most with the insides of pipes and large chimneys! You can see in the screenshot that I have not placed any layer 2 walls behind the pipe segments at the bottom of the room’s vat area. I’ve done this so that the back wall will not cover over the inside of the pipes during the render! Once you are done painting, save, export text, and do a render! Lets do another test of how our level looks! == A Third Render == [[File:rfg-9.png|thumb|none|alt=9|9]] Yet another render, and more to see and tweak! We can fix any mistakes easily as we go. You can also skip each rendering step, and do all the layers at once if you are confident with the editor! I’ll be doing a third layer, and correcting all the issues on layer 2 by the next section. All the info you need is in the official editor’s article here: [[Level Editor]]. There is also a large guide of all tiles and materials, and how they look once rendered here: https://imgur.com/a/Vz3Kk The next steps involve tweaking, rendering, retweaking, and rerendering until you are happy with the base design of your level! Remember, that some creatures use layer 2 to climb on walls, but layer 3 is far enough in the background for nothing to interact with it! Layer 1 is solid to all creatures with few if at all exceptions. Make sure you cannot get trapped in your level! == Effects and You == [[File:rfg-10.png|thumb|none|alt=10|10]] It’s time to start painting! Now that you’ve solved any issues on your tile layers, and painted yourself a background layer. You are now ready to start painting effects! Remember though. Each effect slows down the render of the level quite a bit. From now on it will begin to get more time consuming to fix mistakes in the level! Especially once you start making larger rooms! Effects are what make Rain World rooms look special. They alter, distort, and deform your tiles. Grow plants, and even alter tiles entirely! The effects editor has an example image of every effect, and its basic usage outline in this article: [[level-editor/Effect-Editor|Effects Editor]]. For the basics though! BlackGoo and Slime; These two effects are used in nearly every screen in Rain World to some degree! Slime makes every tile look slightly drippy and goopy. Like a mess has been rubbed onto them. BlackGoo forms the outer “shadow” of rooms. Both of these work together to make your room look less repetitive and clean! == Yet another rendering == [[File:rfg-11.png|thumb|none|alt=11|11]] Look how far we’ve come! From an empty screen with nothing. To a room that feels like it is simply missing “something” before it is finished! Things like the brickwork along the sides passing over the BlackGoo( It only applies itself over certain materials!) can be corrected using large junk or dirt where you would want the BlackGoo down there. You can also apply other effects till you are happy with the room. This includes everything from rubble, distortions, plants, and even daddy long leg corrupted walls! The only limits is your imagination to making effects work together, and the tiles you have to use! Once you’ve applied the effects you want, and have re-rendered till the level looks right. Next up is to add some props to our room! == Fancy Props and Design == [[File:rfg-12.png|thumb|none|alt=12|12]] Remember to always save and keep backups! Some editor tabs can be more fussy then others! Props are used to detail your room even further. Allowing you to place details without the grid, and at any angle and distorted shape you want! The control are outlined in the article here: [[level-editor/Prop-Editor.html|Prop Editor]]. While this is not too complex of a section. Adding a few proper can help break the rather straight geometry normally present in Rain World’s levels by giving them some more curved shapes to look at. Such as tubes and valves between containers or machines! Once you are all setup, we can render and move onto using the dev tools to configure the rooms more fine details! Remember. You can always re-render and re-export a level as many times as you need. At no point does a level become impossible to edit. With the one exception of losing its project save file! == Dev tool configurations == [[File:rfg-13.png|thumb|none|alt=13|13]] We can now move onto using the [[Dev Tools]] to configure the level’s more detailed settings! Everything from the room’s colors, effects, and even how the rain timer affects this room! Want a section of outskirts with some kind of lightning machine? Go ahead! Want to make a flooding cave system? It’s all in here! The room’s palette is not tied to the region. However most regions have “templates” that you can use to automatically set room settings to. Instead of needing to do each room one by one the same way. You can change anything you need to away from the template default, or click “NONE” beneath in the template section to use purely your own settings. The rooms palette can also be configured to fade between it, and another palette. Allowing you to configure the exact colors you would need. The various effects can also be configured to use Color1 or Color2 of the effect palettes. These are used to set the colors of plants. Giant signs, and even daddy long leg corruption! Exploring the dev tools documentation will give you far more info and ideas then me directly telling you every possible situation. Remember that some objects and room settings require a reload of the room to appear! Don’t forget to add sounds and some environmental ambience to flesh out your room, to make it feel like a unique location in this world! ''A very IMPORTANT notice! Be sure to click the save button before you reload the room'' somehow! Or your changes will be lost! All of these configurations are save to ROOMNAME_settings.txt. == Over and Over Again == [[File:rfg-14.png|thumb|none|alt=14|14]] The process of making a full region is filled with this! Making rooms from the ground up, detailing and configuring them, before linking another room onto the chain. The only real difference is that you are doing so from the gates of your own region, instead of a small room connected to the side of outskirts! There are already a few pages of documentation related to connecting in a new region yourself! The main one can be found here: [[Adding-A-New-Region.html|Adding new Regions]]. The details of how to setup creatures and connections for the region are here: [[World File Format]]. Finally, the dev tool’s map editor for making your region properly show as a map in game is here: [[Dev_Tools#Interface_Tabs#Map-0|Map Tab]]. I’ll likely be expanding this guide at some point in the future, but for now this is the basics of how to create a room from scratch! Look through the other articles for things like: Raising the water level, setting up creature spawns, understanding doors, adding food, placing objects and plants, adding sounds and effects, specific room triggers, and the various special room settings! And remember! Have fun! == Why Do My Rooms Crash? == There are multiple reasons Rain World will dislike your rooms or connections. These are a few common, and more niche reasons why the game may be crashing. === Doors outside of room bounds: === ALWAYS place every part of a short cut’s path inside the room’s boundary. Any short cut paths outside of it are ignored and will break the game when loaded. Crashing to a grey screen on file load. === Accidental Doors and Dens: === The editor is a strange tool. It also has a second cursor in geometry mode… for some reason. An accidental key press may have placed a den, short cut entrance, or other kind of door in the room without proper connections. Take a peak over your room for any issues. === Incorrect Region Prefix: === the prefix at the start of a room file should match the region you are placing it inside. For this guide we focus on tests rooms inside of outskirts ( SU_ ). If you are bringing these rooms to a custom region by renaming them, be sure to open the room’s data file, and edit the first line to match the renamed version of the file. [[Category:Content Mods]] 316ac1d289f49fc9e86c1a03c17a194a1454600a 341 340 2022-09-11T01:50:01Z MACMAN2003 21 /* Effects and You */ fixed broken link wikitext text/x-wiki {{Cleanup}} {{todo|target=page}} So you want to make a region, but you have no clue where to start! The idea of modding something so big is certainly daunting! However, looking at everything in small repeatable pieces will let you work step by step until one day you’ll suddenly have a finished region! However before that happens you need to learn some basics to get you started! Lets start with some terminology of the tools used! * [[Level Editor]] - This is the tool given to the modding community by the Rain World developers. These are the actual tools used to make Rain World. However much of its features and hotkeys are difficult and quirky to work with at first, but given enough time and use, the editor becomes an extremely powerful tool. * Unofficial level editor - This is a tool created by AndrewFM and Mikronaut to edit Rain World rooms before the official editor was released. While it lacks many features needed to make rooms. It does have the incredibly useful feature of being able to edit already exported rooms. As well as changing creature dens into doors, and vice versa. * [[Dev Tools]] - These are in game tools Rain World uses for editing room visual effects, sounds, and triggers. As well as the regions map, and the various other specific configurations of your room! * [[World File Format]] - This controls how your region (or any other region!) binds rooms together. As well as creature spawns! * Room settings text - These files are present for every room that you save a configuration for in the dev tools. It contains the placement of objects, sounds, room effects, and any other setting applied using the dev tools. I will not be giving a full control outline for every editor in this tutorial. If you need the editor’s controls, please see the full article on the specific tool you are using for their list of inputs and quirks. This article is an exercise in how to bring a level from an empty screen, to a fully fleshed out room. Largely following my own process. Don’t be afraid to branch out and try weirder things as you get comfortable with the editor! == Important terms and info == * A region is a large collection of connected rooms. Using a Worldfile to setup data inside them. * A room is stored as several files that contain: ** Geometry and pathfinding data ** Room graphics, one .PNG file per camera ** Settings file containing additional data such as room effects, sound triggers and placed objects (defined in [[Dev Tools]]) * The editor can only export the collision and graphics for rooms, Dev Tools are used to set the colors and effects. * Every room needs at least one valid door in order to be connected * By default, the editor will create a room the correct size for a single screen, with a single camera already set up. <!--This is why the guide assumes only a single screen to help you learn to use the editor.--> By default, a single room is 72 x 43. '''Changing room size after some tiles have been added breaks the tiles, and has a chance of corrupting the level project with uneraseable invisible tiles!''' == Setting Up == [[File:rfg-1.png|thumb|none|alt=1|1]] Once you open the official editor for the first time. you will be greeted with a file select. It is advised to make a folder for your rooms to keep them organized before you open the editor. Use the arrow keys to navigate into that folder, and press N to make a new room. You will then be greeted with the editor’s main menu. === Saving, and name quirks: === Before we do anything, lets save our room. It is REQUIRED that you start all of your rooms names with a region prefix. You can check the Rain World, World folder for the regions in game. We will be using SU_ the prefix for outskirts, at least until we have several rooms for our region later, or you are confident enough to begin making rooms for your own region. Secondly, NEVER use spaces. Always use an underscore _ to separate your name’s sections. Examples of correct room names: * SU_test01 * SU_myroom * SU_my_room * SU_another_room * SU_lotsandlotsofroom15 * SU_A04 The developers often used the letter (A, B, C…, J…) after the underscore _ to track the number of cameras in the room (for non-shelter (S) rooms), but this is not required. Examples of actual rooms in the game: * SU_A05 - small Outskirts room with 1 camera (A) * SU_B08 - larger Outskirts room with 2 cameras (B) * HI_C14 - wide Industrial Complex room with 3 cameras (C) * CC_D01 - tall Chimney Canopy room with 4 cameras (D) * SL_F01 - Shoreline room with 6 cameras (F) * UW_J01 - huge room in The Wall with 10 cameras (J) So now. You are ready to begin painting! == A Blank Canvas == [[File:rfg-2.png|thumb|none|alt=2|2]] Click the geometry editor button to begin painting your level’s basic geometry. However, before we do anything. We will first clear all the layer using the “clear all” tool. Use the arrow keys while the mouse is over the tile grid to change tools. Once the red box is over the X shaped tool. Used the numpad to navigate to the top left corner, click once to start drawing the rectangle of the clear tool, and navigate to the bottom right to place the other corner. When you are finished all the solid walls in the room will be removed. Leaving you with a completely blank canvas to work from. A “fuzzy” grey border marks the very edge of a room. Where tiles no longer exist to the game. The white rectangle is the game play border Anything outside of this will repeat off into the distance, this ONLY applies to the room’s collision. Visually they will be fine. All room in Rain World use these borders. For a more simple explanation. Keep everything related to gameplay inside the white rectangle! Anything outside will only show up visually, but will not act the same as they would inside the rectangle! == Blocking It Out == [[File:rfg-3.png|thumb|none|alt=3|3]] Lets start painting out the shapes we want for our basic level! This seems like a bit sudden of a jump, but only a few moments of messing around in the editor will let you achieve what you see in the screenshot! Short cuts to doors and dens require walls to be placed in specific ways around them. The [[Level Editor#Editors|Geometry Editor]] article goes into more depth about properly connecting short cuts, doors, and dens. For now, we will simply place walls, some poles, and at least one “Entrance” to the room. The Dens seen in the screenshot are optional. Only one door is required for this tutorial. == A Test Render == [[File:rfg-4.png|thumb|none|alt=4|4]] Before we move on; Lets do another save. So if anything goes wrong we won’t lose the level geometry we now have. Press 1 on the number row to return to the main menu, and press the save button! Press enter in the name field to save the room without changing the name of it. It is now time to do a test render of our room so we can see if it plays correctly in game! First, we need to click “Text Output” to save the levels collision data, and then press “Render Level.” The editor will appear to freeze for a few moments. This is normal! Do not be worried, or attempt to close the editor! Eventually the editor will begin processing each layer of the room. Before it will render the rooms data into a red and black image. The files will be output into the “Levels” folder by the editor’s executable. The files ROOMNAME.txt and ROOMNAME_1.png are the exported version of your room, for use by Rain Worlds engine. Lets get to seeing our room in game! == Our First Link == For now. We will be using outskirts as a quick way to test our room. We don’t have our own region yet after all! There is already an easy to use DISCONNECTED door in outskirts, close to the start of the game. Lets move our room files to where they are needed! First. Copy the ROOMNAME.txt and ROOMNAME_1.png files from the editor’s level export folder. Then navigate to “Rain World”. Inside you will see various other room files, and their settings file. For now, we will simply paste our room files into this folder. Second. We will go one folder up. So we are inside the “SU” region folder. In here you will see Outskirt’s World.txt file. The detail of this file are in this article: [[World File Format]]. However, for the purpose of this tutorial, we will be following the next steps to install our room to Outskirts! Third. Open World_SU.txt. Inside we will see several door connections, creature spawns, and other region related data. Look for the line: * SU_A63 : SU_B12, SU_A37, DISCONNECTED This room has a disconnected door we can use to hook our room into easily! Lets add our room into the file! At the end of the end of the ROOMS section, but before the END ROOMS tag, add in our room’s name. Followed by a : Then add SU_A63. This will link our door to SU_A63. My room’s entry looks like this: * SU_myroom : SU_A63 We now need to make sure SU_A63 connects to our room as well! We simply need to change DISCONNECTED into our rooms name. Mine looks like: * SU_A63 : SU_B12, SU_A37, SU_myroom We can now start Rain World! If this has all been done correctly. Then you will be able to load your file without it crashing to a grey screen. Simply navigate to SU_A63 to see the freshly added connection! You can peak into SU’s “Rooms” folder, and find SU_A63_1.png to see what the room looks like to know where it is in game! == Making Mistakes == [[File:rfg-5.png|thumb|none|alt=5|5]] Our first room is pretty rough! Not everything will be perfect of course! This is a time to see if everything in our geometry works right! If pits are impossible to jump across, or if a jump is just a little our of reach. This is the time to tweak our level till we are happy with the layout. Render times are very fast with just a single layer and some walls after all! Don’t be afraid of mistakes at this point. Just fix them and tweak until your room feels like it is playable, and there are no locations that you can become stuck in. Repeat the steps above to edit, re-render, and re-install the room. You will no longer need to link the level to the world again! You only need to update the room files and image. You do not even need to close Rain World to test these changes. Simply dying, and returning to the room is enough to cause the room to reload for you to test the new collisions! == A Start To Detailing == [[File:rfg-6.png|thumb|none|alt=6|6]] This looks like another crazy jump! But once you get used to the materials the editor gives you, the tile editor will become a playground, and you may even start designing your levels with it, and instead use the geometry editor just to compliment your tiles! It will all come to you as your understanding and comfort of the editor increases. The details I’ve applied myself, have been to paint various materials in the same style Outskirts uses. Large metal plates surrounding dense pipes on corners. Concrete as the base material. The rare inclusion of pipes and machines. Along with a few things I enjoy using in my own levels. Such as large signs from the Misc category, and the insides of large pipes! The tile menu can be navigated using WASD keys. Many large tiles have a collision requirement. Holding G while clicking will automatically place the required geometry for you. This allows you to build things like pipes or complex machines without revisiting the geometry editor, or to construct rooms almost entirely out of tiles. However, you will still need to visit the geometry editor at some point for the bulk of your room’s padding. Where you will paint the traditional tile “materials” over solid walls. The colored dots in the picture are walls painted with a specific material. These are applied as the level is rendered! For now we are still just focusing on layer 1! == A Second Render == [[File:rfg-7.png|thumb|none|alt=7|7]] Things are starting to come together now! We can do a second little peak at how the room plays. After all, we’ve likely done some tweaks with our detailing. Something is still missing however. Using only the first layer of Rain World’s rooms can only give us so much detail! This level needs some DEPTH! == Depth, and the Art of Backgrounds == [[File:rfg-8.png|thumb|none|alt=8|8]] Lets head back into the editor! In the geometry editor, use the layer tool in the bottom left to change to layer 2, and paint over the places we want to place a “back wall” to our room! This layer is also one that creatures can climb on. Blue lizards often do this! Some details on the first layer will also “bleed” into layers behind them. This happens most with the insides of pipes and large chimneys! You can see in the screenshot that I have not placed any layer 2 walls behind the pipe segments at the bottom of the room’s vat area. I’ve done this so that the back wall will not cover over the inside of the pipes during the render! Once you are done painting, save, export text, and do a render! Lets do another test of how our level looks! == A Third Render == [[File:rfg-9.png|thumb|none|alt=9|9]] Yet another render, and more to see and tweak! We can fix any mistakes easily as we go. You can also skip each rendering step, and do all the layers at once if you are confident with the editor! I’ll be doing a third layer, and correcting all the issues on layer 2 by the next section. All the info you need is in the official editor’s article here: [[Level Editor]]. There is also a large guide of all tiles and materials, and how they look once rendered here: https://imgur.com/a/Vz3Kk The next steps involve tweaking, rendering, retweaking, and rerendering until you are happy with the base design of your level! Remember, that some creatures use layer 2 to climb on walls, but layer 3 is far enough in the background for nothing to interact with it! Layer 1 is solid to all creatures with few if at all exceptions. Make sure you cannot get trapped in your level! == Effects and You == [[File:rfg-10.png|thumb|none|alt=10|10]] It’s time to start painting! Now that you’ve solved any issues on your tile layers, and painted yourself a background layer. You are now ready to start painting effects! Remember though. Each effect slows down the render of the level quite a bit. From now on it will begin to get more time consuming to fix mistakes in the level! Especially once you start making larger rooms! Effects are what make Rain World rooms look special. They alter, distort, and deform your tiles. Grow plants, and even alter tiles entirely! The effects editor has an example image of every effect, and its basic usage outline in this article: [[Level Editor#Editors|Effects Editor]]. For the basics though! BlackGoo and Slime; These two effects are used in nearly every screen in Rain World to some degree! Slime makes every tile look slightly drippy and goopy. Like a mess has been rubbed onto them. BlackGoo forms the outer “shadow” of rooms. Both of these work together to make your room look less repetitive and clean! == Yet another rendering == [[File:rfg-11.png|thumb|none|alt=11|11]] Look how far we’ve come! From an empty screen with nothing. To a room that feels like it is simply missing “something” before it is finished! Things like the brickwork along the sides passing over the BlackGoo( It only applies itself over certain materials!) can be corrected using large junk or dirt where you would want the BlackGoo down there. You can also apply other effects till you are happy with the room. This includes everything from rubble, distortions, plants, and even daddy long leg corrupted walls! The only limits is your imagination to making effects work together, and the tiles you have to use! Once you’ve applied the effects you want, and have re-rendered till the level looks right. Next up is to add some props to our room! == Fancy Props and Design == [[File:rfg-12.png|thumb|none|alt=12|12]] Remember to always save and keep backups! Some editor tabs can be more fussy then others! Props are used to detail your room even further. Allowing you to place details without the grid, and at any angle and distorted shape you want! The control are outlined in the article here: [[level-editor/Prop-Editor.html|Prop Editor]]. While this is not too complex of a section. Adding a few proper can help break the rather straight geometry normally present in Rain World’s levels by giving them some more curved shapes to look at. Such as tubes and valves between containers or machines! Once you are all setup, we can render and move onto using the dev tools to configure the rooms more fine details! Remember. You can always re-render and re-export a level as many times as you need. At no point does a level become impossible to edit. With the one exception of losing its project save file! == Dev tool configurations == [[File:rfg-13.png|thumb|none|alt=13|13]] We can now move onto using the [[Dev Tools]] to configure the level’s more detailed settings! Everything from the room’s colors, effects, and even how the rain timer affects this room! Want a section of outskirts with some kind of lightning machine? Go ahead! Want to make a flooding cave system? It’s all in here! The room’s palette is not tied to the region. However most regions have “templates” that you can use to automatically set room settings to. Instead of needing to do each room one by one the same way. You can change anything you need to away from the template default, or click “NONE” beneath in the template section to use purely your own settings. The rooms palette can also be configured to fade between it, and another palette. Allowing you to configure the exact colors you would need. The various effects can also be configured to use Color1 or Color2 of the effect palettes. These are used to set the colors of plants. Giant signs, and even daddy long leg corruption! Exploring the dev tools documentation will give you far more info and ideas then me directly telling you every possible situation. Remember that some objects and room settings require a reload of the room to appear! Don’t forget to add sounds and some environmental ambience to flesh out your room, to make it feel like a unique location in this world! ''A very IMPORTANT notice! Be sure to click the save button before you reload the room'' somehow! Or your changes will be lost! All of these configurations are save to ROOMNAME_settings.txt. == Over and Over Again == [[File:rfg-14.png|thumb|none|alt=14|14]] The process of making a full region is filled with this! Making rooms from the ground up, detailing and configuring them, before linking another room onto the chain. The only real difference is that you are doing so from the gates of your own region, instead of a small room connected to the side of outskirts! There are already a few pages of documentation related to connecting in a new region yourself! The main one can be found here: [[Adding-A-New-Region.html|Adding new Regions]]. The details of how to setup creatures and connections for the region are here: [[World File Format]]. Finally, the dev tool’s map editor for making your region properly show as a map in game is here: [[Dev_Tools#Interface_Tabs#Map-0|Map Tab]]. I’ll likely be expanding this guide at some point in the future, but for now this is the basics of how to create a room from scratch! Look through the other articles for things like: Raising the water level, setting up creature spawns, understanding doors, adding food, placing objects and plants, adding sounds and effects, specific room triggers, and the various special room settings! And remember! Have fun! == Why Do My Rooms Crash? == There are multiple reasons Rain World will dislike your rooms or connections. These are a few common, and more niche reasons why the game may be crashing. === Doors outside of room bounds: === ALWAYS place every part of a short cut’s path inside the room’s boundary. Any short cut paths outside of it are ignored and will break the game when loaded. Crashing to a grey screen on file load. === Accidental Doors and Dens: === The editor is a strange tool. It also has a second cursor in geometry mode… for some reason. An accidental key press may have placed a den, short cut entrance, or other kind of door in the room without proper connections. Take a peak over your room for any issues. === Incorrect Region Prefix: === the prefix at the start of a room file should match the region you are placing it inside. For this guide we focus on tests rooms inside of outskirts ( SU_ ). If you are bringing these rooms to a custom region by renaming them, be sure to open the room’s data file, and edit the first line to match the renamed version of the file. [[Category:Content Mods]] c1d559e2c88bdf0bdde266559e30be3d6f6a701b 342 341 2022-09-11T01:50:57Z MACMAN2003 21 /* Fancy Props and Design */ fixed broken link wikitext text/x-wiki {{Cleanup}} {{todo|target=page}} So you want to make a region, but you have no clue where to start! The idea of modding something so big is certainly daunting! However, looking at everything in small repeatable pieces will let you work step by step until one day you’ll suddenly have a finished region! However before that happens you need to learn some basics to get you started! Lets start with some terminology of the tools used! * [[Level Editor]] - This is the tool given to the modding community by the Rain World developers. These are the actual tools used to make Rain World. However much of its features and hotkeys are difficult and quirky to work with at first, but given enough time and use, the editor becomes an extremely powerful tool. * Unofficial level editor - This is a tool created by AndrewFM and Mikronaut to edit Rain World rooms before the official editor was released. While it lacks many features needed to make rooms. It does have the incredibly useful feature of being able to edit already exported rooms. As well as changing creature dens into doors, and vice versa. * [[Dev Tools]] - These are in game tools Rain World uses for editing room visual effects, sounds, and triggers. As well as the regions map, and the various other specific configurations of your room! * [[World File Format]] - This controls how your region (or any other region!) binds rooms together. As well as creature spawns! * Room settings text - These files are present for every room that you save a configuration for in the dev tools. It contains the placement of objects, sounds, room effects, and any other setting applied using the dev tools. I will not be giving a full control outline for every editor in this tutorial. If you need the editor’s controls, please see the full article on the specific tool you are using for their list of inputs and quirks. This article is an exercise in how to bring a level from an empty screen, to a fully fleshed out room. Largely following my own process. Don’t be afraid to branch out and try weirder things as you get comfortable with the editor! == Important terms and info == * A region is a large collection of connected rooms. Using a Worldfile to setup data inside them. * A room is stored as several files that contain: ** Geometry and pathfinding data ** Room graphics, one .PNG file per camera ** Settings file containing additional data such as room effects, sound triggers and placed objects (defined in [[Dev Tools]]) * The editor can only export the collision and graphics for rooms, Dev Tools are used to set the colors and effects. * Every room needs at least one valid door in order to be connected * By default, the editor will create a room the correct size for a single screen, with a single camera already set up. <!--This is why the guide assumes only a single screen to help you learn to use the editor.--> By default, a single room is 72 x 43. '''Changing room size after some tiles have been added breaks the tiles, and has a chance of corrupting the level project with uneraseable invisible tiles!''' == Setting Up == [[File:rfg-1.png|thumb|none|alt=1|1]] Once you open the official editor for the first time. you will be greeted with a file select. It is advised to make a folder for your rooms to keep them organized before you open the editor. Use the arrow keys to navigate into that folder, and press N to make a new room. You will then be greeted with the editor’s main menu. === Saving, and name quirks: === Before we do anything, lets save our room. It is REQUIRED that you start all of your rooms names with a region prefix. You can check the Rain World, World folder for the regions in game. We will be using SU_ the prefix for outskirts, at least until we have several rooms for our region later, or you are confident enough to begin making rooms for your own region. Secondly, NEVER use spaces. Always use an underscore _ to separate your name’s sections. Examples of correct room names: * SU_test01 * SU_myroom * SU_my_room * SU_another_room * SU_lotsandlotsofroom15 * SU_A04 The developers often used the letter (A, B, C…, J…) after the underscore _ to track the number of cameras in the room (for non-shelter (S) rooms), but this is not required. Examples of actual rooms in the game: * SU_A05 - small Outskirts room with 1 camera (A) * SU_B08 - larger Outskirts room with 2 cameras (B) * HI_C14 - wide Industrial Complex room with 3 cameras (C) * CC_D01 - tall Chimney Canopy room with 4 cameras (D) * SL_F01 - Shoreline room with 6 cameras (F) * UW_J01 - huge room in The Wall with 10 cameras (J) So now. You are ready to begin painting! == A Blank Canvas == [[File:rfg-2.png|thumb|none|alt=2|2]] Click the geometry editor button to begin painting your level’s basic geometry. However, before we do anything. We will first clear all the layer using the “clear all” tool. Use the arrow keys while the mouse is over the tile grid to change tools. Once the red box is over the X shaped tool. Used the numpad to navigate to the top left corner, click once to start drawing the rectangle of the clear tool, and navigate to the bottom right to place the other corner. When you are finished all the solid walls in the room will be removed. Leaving you with a completely blank canvas to work from. A “fuzzy” grey border marks the very edge of a room. Where tiles no longer exist to the game. The white rectangle is the game play border Anything outside of this will repeat off into the distance, this ONLY applies to the room’s collision. Visually they will be fine. All room in Rain World use these borders. For a more simple explanation. Keep everything related to gameplay inside the white rectangle! Anything outside will only show up visually, but will not act the same as they would inside the rectangle! == Blocking It Out == [[File:rfg-3.png|thumb|none|alt=3|3]] Lets start painting out the shapes we want for our basic level! This seems like a bit sudden of a jump, but only a few moments of messing around in the editor will let you achieve what you see in the screenshot! Short cuts to doors and dens require walls to be placed in specific ways around them. The [[Level Editor#Editors|Geometry Editor]] article goes into more depth about properly connecting short cuts, doors, and dens. For now, we will simply place walls, some poles, and at least one “Entrance” to the room. The Dens seen in the screenshot are optional. Only one door is required for this tutorial. == A Test Render == [[File:rfg-4.png|thumb|none|alt=4|4]] Before we move on; Lets do another save. So if anything goes wrong we won’t lose the level geometry we now have. Press 1 on the number row to return to the main menu, and press the save button! Press enter in the name field to save the room without changing the name of it. It is now time to do a test render of our room so we can see if it plays correctly in game! First, we need to click “Text Output” to save the levels collision data, and then press “Render Level.” The editor will appear to freeze for a few moments. This is normal! Do not be worried, or attempt to close the editor! Eventually the editor will begin processing each layer of the room. Before it will render the rooms data into a red and black image. The files will be output into the “Levels” folder by the editor’s executable. The files ROOMNAME.txt and ROOMNAME_1.png are the exported version of your room, for use by Rain Worlds engine. Lets get to seeing our room in game! == Our First Link == For now. We will be using outskirts as a quick way to test our room. We don’t have our own region yet after all! There is already an easy to use DISCONNECTED door in outskirts, close to the start of the game. Lets move our room files to where they are needed! First. Copy the ROOMNAME.txt and ROOMNAME_1.png files from the editor’s level export folder. Then navigate to “Rain World”. Inside you will see various other room files, and their settings file. For now, we will simply paste our room files into this folder. Second. We will go one folder up. So we are inside the “SU” region folder. In here you will see Outskirt’s World.txt file. The detail of this file are in this article: [[World File Format]]. However, for the purpose of this tutorial, we will be following the next steps to install our room to Outskirts! Third. Open World_SU.txt. Inside we will see several door connections, creature spawns, and other region related data. Look for the line: * SU_A63 : SU_B12, SU_A37, DISCONNECTED This room has a disconnected door we can use to hook our room into easily! Lets add our room into the file! At the end of the end of the ROOMS section, but before the END ROOMS tag, add in our room’s name. Followed by a : Then add SU_A63. This will link our door to SU_A63. My room’s entry looks like this: * SU_myroom : SU_A63 We now need to make sure SU_A63 connects to our room as well! We simply need to change DISCONNECTED into our rooms name. Mine looks like: * SU_A63 : SU_B12, SU_A37, SU_myroom We can now start Rain World! If this has all been done correctly. Then you will be able to load your file without it crashing to a grey screen. Simply navigate to SU_A63 to see the freshly added connection! You can peak into SU’s “Rooms” folder, and find SU_A63_1.png to see what the room looks like to know where it is in game! == Making Mistakes == [[File:rfg-5.png|thumb|none|alt=5|5]] Our first room is pretty rough! Not everything will be perfect of course! This is a time to see if everything in our geometry works right! If pits are impossible to jump across, or if a jump is just a little our of reach. This is the time to tweak our level till we are happy with the layout. Render times are very fast with just a single layer and some walls after all! Don’t be afraid of mistakes at this point. Just fix them and tweak until your room feels like it is playable, and there are no locations that you can become stuck in. Repeat the steps above to edit, re-render, and re-install the room. You will no longer need to link the level to the world again! You only need to update the room files and image. You do not even need to close Rain World to test these changes. Simply dying, and returning to the room is enough to cause the room to reload for you to test the new collisions! == A Start To Detailing == [[File:rfg-6.png|thumb|none|alt=6|6]] This looks like another crazy jump! But once you get used to the materials the editor gives you, the tile editor will become a playground, and you may even start designing your levels with it, and instead use the geometry editor just to compliment your tiles! It will all come to you as your understanding and comfort of the editor increases. The details I’ve applied myself, have been to paint various materials in the same style Outskirts uses. Large metal plates surrounding dense pipes on corners. Concrete as the base material. The rare inclusion of pipes and machines. Along with a few things I enjoy using in my own levels. Such as large signs from the Misc category, and the insides of large pipes! The tile menu can be navigated using WASD keys. Many large tiles have a collision requirement. Holding G while clicking will automatically place the required geometry for you. This allows you to build things like pipes or complex machines without revisiting the geometry editor, or to construct rooms almost entirely out of tiles. However, you will still need to visit the geometry editor at some point for the bulk of your room’s padding. Where you will paint the traditional tile “materials” over solid walls. The colored dots in the picture are walls painted with a specific material. These are applied as the level is rendered! For now we are still just focusing on layer 1! == A Second Render == [[File:rfg-7.png|thumb|none|alt=7|7]] Things are starting to come together now! We can do a second little peak at how the room plays. After all, we’ve likely done some tweaks with our detailing. Something is still missing however. Using only the first layer of Rain World’s rooms can only give us so much detail! This level needs some DEPTH! == Depth, and the Art of Backgrounds == [[File:rfg-8.png|thumb|none|alt=8|8]] Lets head back into the editor! In the geometry editor, use the layer tool in the bottom left to change to layer 2, and paint over the places we want to place a “back wall” to our room! This layer is also one that creatures can climb on. Blue lizards often do this! Some details on the first layer will also “bleed” into layers behind them. This happens most with the insides of pipes and large chimneys! You can see in the screenshot that I have not placed any layer 2 walls behind the pipe segments at the bottom of the room’s vat area. I’ve done this so that the back wall will not cover over the inside of the pipes during the render! Once you are done painting, save, export text, and do a render! Lets do another test of how our level looks! == A Third Render == [[File:rfg-9.png|thumb|none|alt=9|9]] Yet another render, and more to see and tweak! We can fix any mistakes easily as we go. You can also skip each rendering step, and do all the layers at once if you are confident with the editor! I’ll be doing a third layer, and correcting all the issues on layer 2 by the next section. All the info you need is in the official editor’s article here: [[Level Editor]]. There is also a large guide of all tiles and materials, and how they look once rendered here: https://imgur.com/a/Vz3Kk The next steps involve tweaking, rendering, retweaking, and rerendering until you are happy with the base design of your level! Remember, that some creatures use layer 2 to climb on walls, but layer 3 is far enough in the background for nothing to interact with it! Layer 1 is solid to all creatures with few if at all exceptions. Make sure you cannot get trapped in your level! == Effects and You == [[File:rfg-10.png|thumb|none|alt=10|10]] It’s time to start painting! Now that you’ve solved any issues on your tile layers, and painted yourself a background layer. You are now ready to start painting effects! Remember though. Each effect slows down the render of the level quite a bit. From now on it will begin to get more time consuming to fix mistakes in the level! Especially once you start making larger rooms! Effects are what make Rain World rooms look special. They alter, distort, and deform your tiles. Grow plants, and even alter tiles entirely! The effects editor has an example image of every effect, and its basic usage outline in this article: [[Level Editor#Editors|Effects Editor]]. For the basics though! BlackGoo and Slime; These two effects are used in nearly every screen in Rain World to some degree! Slime makes every tile look slightly drippy and goopy. Like a mess has been rubbed onto them. BlackGoo forms the outer “shadow” of rooms. Both of these work together to make your room look less repetitive and clean! == Yet another rendering == [[File:rfg-11.png|thumb|none|alt=11|11]] Look how far we’ve come! From an empty screen with nothing. To a room that feels like it is simply missing “something” before it is finished! Things like the brickwork along the sides passing over the BlackGoo( It only applies itself over certain materials!) can be corrected using large junk or dirt where you would want the BlackGoo down there. You can also apply other effects till you are happy with the room. This includes everything from rubble, distortions, plants, and even daddy long leg corrupted walls! The only limits is your imagination to making effects work together, and the tiles you have to use! Once you’ve applied the effects you want, and have re-rendered till the level looks right. Next up is to add some props to our room! == Fancy Props and Design == [[File:rfg-12.png|thumb|none|alt=12|12]] Remember to always save and keep backups! Some editor tabs can be more fussy then others! Props are used to detail your room even further. Allowing you to place details without the grid, and at any angle and distorted shape you want! The control are outlined in the article here: [[Level Editor#Editors|Prop Editor]]. While this is not too complex of a section. Adding a few proper can help break the rather straight geometry normally present in Rain World’s levels by giving them some more curved shapes to look at. Such as tubes and valves between containers or machines! Once you are all setup, we can render and move onto using the dev tools to configure the rooms more fine details! Remember. You can always re-render and re-export a level as many times as you need. At no point does a level become impossible to edit. With the one exception of losing its project save file! == Dev tool configurations == [[File:rfg-13.png|thumb|none|alt=13|13]] We can now move onto using the [[Dev Tools]] to configure the level’s more detailed settings! Everything from the room’s colors, effects, and even how the rain timer affects this room! Want a section of outskirts with some kind of lightning machine? Go ahead! Want to make a flooding cave system? It’s all in here! The room’s palette is not tied to the region. However most regions have “templates” that you can use to automatically set room settings to. Instead of needing to do each room one by one the same way. You can change anything you need to away from the template default, or click “NONE” beneath in the template section to use purely your own settings. The rooms palette can also be configured to fade between it, and another palette. Allowing you to configure the exact colors you would need. The various effects can also be configured to use Color1 or Color2 of the effect palettes. These are used to set the colors of plants. Giant signs, and even daddy long leg corruption! Exploring the dev tools documentation will give you far more info and ideas then me directly telling you every possible situation. Remember that some objects and room settings require a reload of the room to appear! Don’t forget to add sounds and some environmental ambience to flesh out your room, to make it feel like a unique location in this world! ''A very IMPORTANT notice! Be sure to click the save button before you reload the room'' somehow! Or your changes will be lost! All of these configurations are save to ROOMNAME_settings.txt. == Over and Over Again == [[File:rfg-14.png|thumb|none|alt=14|14]] The process of making a full region is filled with this! Making rooms from the ground up, detailing and configuring them, before linking another room onto the chain. The only real difference is that you are doing so from the gates of your own region, instead of a small room connected to the side of outskirts! There are already a few pages of documentation related to connecting in a new region yourself! The main one can be found here: [[Adding-A-New-Region.html|Adding new Regions]]. The details of how to setup creatures and connections for the region are here: [[World File Format]]. Finally, the dev tool’s map editor for making your region properly show as a map in game is here: [[Dev_Tools#Interface_Tabs#Map-0|Map Tab]]. I’ll likely be expanding this guide at some point in the future, but for now this is the basics of how to create a room from scratch! Look through the other articles for things like: Raising the water level, setting up creature spawns, understanding doors, adding food, placing objects and plants, adding sounds and effects, specific room triggers, and the various special room settings! And remember! Have fun! == Why Do My Rooms Crash? == There are multiple reasons Rain World will dislike your rooms or connections. These are a few common, and more niche reasons why the game may be crashing. === Doors outside of room bounds: === ALWAYS place every part of a short cut’s path inside the room’s boundary. Any short cut paths outside of it are ignored and will break the game when loaded. Crashing to a grey screen on file load. === Accidental Doors and Dens: === The editor is a strange tool. It also has a second cursor in geometry mode… for some reason. An accidental key press may have placed a den, short cut entrance, or other kind of door in the room without proper connections. Take a peak over your room for any issues. === Incorrect Region Prefix: === the prefix at the start of a room file should match the region you are placing it inside. For this guide we focus on tests rooms inside of outskirts ( SU_ ). If you are bringing these rooms to a custom region by renaming them, be sure to open the room’s data file, and edit the first line to match the renamed version of the file. [[Category:Content Mods]] e661f3f1beff8c398bfd0c978dfc4953540ba4f2 Downpour Reference/Mod Directories 0 145 343 281 2022-09-18T18:59:27Z AndrewFM 14 Metadata update wikitext text/x-wiki Each mod in Downpour is stored as a subfolder inside the &quot;Assets/StreamingAssets/mods&quot; directory. This subfolder contains all metadata, file modifications and overrides, assets, and code modules (DLL files) that define the mod's contents and functionality. == ModInfo JSON == Each mod should have a &quot;modinfo.json&quot; file included in the top level directory of the mod. This JSON file defines the metadata for the mod, mainly the information that will be displayed for that mod within the REMIX menu. The following key-value pairs exist for this JSON file: {|class="wikitable" ! Key !! Meaning |- | id || This is a unique string identifier for this mod. This identifier should never be changed. Recommended to be a lower-case string with no spaces. Other mods will reference this ID to refer to your mod, such as when listing mod requirements. |- | name || This is the title of your mod that will be shown and listed in the REMIX menu. |- | version || This is a string specifying the current version number of your mod. |- | target_game_version || The version number of Rain World this mod was made for. |- | authors || A string listing the authors of the mod. The &lt;LINE&gt; keyword can be used to add a breakline. If the authors string is too long to be displayed directly, it will be converted to a credits roll in the REMIX menu. |- | description || A longer description of the functionality of the mod, to be displayed in the REMIX menu. The &lt;LINE&gt; keyword can be used to add a breakline. |- | youtube_trailer_id || Optionally, specify the ID for a YouTube video to associate with this mod as a preview trailer. The ID is the text after ?v= in a YouTube video URL. |- | requirements || An array of strings specifying other mods which must be installed to use this mod. Each string in the array should match the '''id''' key of the required mod. |- | requirements_names || A parallel array to the '''requirements''' array, which you can use to display more user friendly names for the requirements in the REMIX menu rather than displaying their internal '''id''' string. |- | checksum_override_version || An optional boolean parameter. If false, or omitted, the mod will be considered &quot;updated&quot; if changes are found to any files in the mod's folder. If true, the mod will only be considered &quot;updated&quot; if the value of the '''version''' parameter changes. |} An example modinfo.json file contents: <syntaxhighlight lang="json"> { "id": "testmod", "name": "Test Mod", "version": "1.0", "target_game_version": "1.5", "authors": "AndrewFM", "description": "This mod does something interesting, probably!", "youtube_trailer_id": "u-cuf39rK8g", "requirements": ["bestmod", "vrmod"], "requirements_names": ["That Other Mod", "Virtual Reality Support"], "checksum_override_version": false } </syntaxhighlight> In addition to the modinfo.json file, the mod directory can also include a '''thumbnail.png''' image to be displayed in the REMIX menu. This should be an image with 16:9 aspect ratio, recommended to be at least 640x360 pixels large. Additionally, the file size of this thumbnail image should remain below 1 MB. == Overwriting Files == The contents of the mod folder are a mirror of the StreamingAssets folder. For example, if you wanted your mod to replace the image file at: <pre>      "Assets/StreamingAssets/futile/resources/illustrations/maintitle.png" </pre> with a different image, you would place the new image at: <pre>      "your-mod-folder/futile/resources/illustrations/maintitle.png" </pre> Since the directory structure and file name match one of the original game's files, the game will use the version from your mod directory instead of the original version of the file, whenever your mod is enabled. In some cases files outside the StreamingAssets folder can be modified as well. For example to modify sound effects (Assets/LoadedSoundEffects) your folder structure would be: <pre>      "your-mod-folder/futile/resources/loadedsoundeffects/..." </pre> Or to modify music files (Assets/Music), the structure would be: <pre>      "your-mod-folder/futile/resources/music/..." </pre> Refer to [[Downpour Reference/Modification Files]] for other ways to modify existing files other than completely overwriting their contents, for better mod compatibility. == AssetManager == Whenever referencing any asset files from disk in your code (whether they be files from within your mod's folder, or files within the base game's folders), you should use the static utility functions offered by the AssetManager class. This ensures the file path to the correct version of the file is used based on which mods are enabled or disabled, following the logic above. For example: <pre>AssetManager.ResolveFilePath(&quot;futile/resources/illustrations/maintitle.png&quot;);</pre> This would return the file path to the vanilla maintitle.png file. However, if the example mod described in the previous section were enabled, this instead would return the file path to that mod's overwritten version of maintitle.png. The available utility functions are: {|class="wikitable" ! Method !! Meaning |- | '''ResolveFilePath(path)''' || Return the correct path to the given file based on enabled/disabled mods. |- | '''ResolveDirectory(path)''' || Return the correct path to the given subdirectory based on enabled/disabled mods. |- | '''ListDirectory(path)''' || Returns all unique files contained in all versions of the given subdirectory based on enabled/disabled mods. |- | '''ListDirectory(path, true)''' || Returns all unique subdirectories contained in all versions of the given subdirectory based on enabled/disabled mods. |} To give an example of ListDirectory, consider a hypothetical vanilla directory at: <pre>      "Assets/StreamingAssets/futile/resources/example"<br /> </pre> which contained the files "a.txt", "b.txt", and "c.txt". Then say you created a mod which included the folder: <pre>      "your-mod-folder/futile/resources/example"<br /> </pre> which contained the files "c.txt", and "d.txt". Then when the code below is executed: <pre> AssetManager.ListDirectory("futile/resources/example"); </pre> If your mod is disabled, the files "a.txt" (vanilla), "b.txt" (vanilla), "c.txt" (vanilla) would be returned. If your mod is enabled, the files "a.txt" (vanilla), "b.txt" (vanilla), "c.txt" (modded), "d.txt" (modded) would be returned. 4942d5a486525f6d7ec2de7284d9017cc2934d5f 354 343 2022-12-30T18:58:32Z AndrewFM 14 Checksum override notes wikitext text/x-wiki Each mod in Downpour is stored as a subfolder inside the &quot;Assets/StreamingAssets/mods&quot; directory. This subfolder contains all metadata, file modifications and overrides, assets, and code modules (DLL files) that define the mod's contents and functionality. == ModInfo JSON == Each mod should have a &quot;modinfo.json&quot; file included in the top level directory of the mod. This JSON file defines the metadata for the mod, mainly the information that will be displayed for that mod within the REMIX menu. The following key-value pairs exist for this JSON file: {|class="wikitable" ! Key !! Meaning |- | id || This is a unique string identifier for this mod. This identifier should never be changed. Recommended to be a lower-case string with no spaces. Other mods will reference this ID to refer to your mod, such as when listing mod requirements. |- | name || This is the title of your mod that will be shown and listed in the REMIX menu. |- | version || This is a string specifying the current version number of your mod. |- | target_game_version || The version number of Rain World this mod was made for. |- | authors || A string listing the authors of the mod. The &lt;LINE&gt; keyword can be used to add a breakline. If the authors string is too long to be displayed directly, it will be converted to a credits roll in the REMIX menu. |- | description || A longer description of the functionality of the mod, to be displayed in the REMIX menu. The &lt;LINE&gt; keyword can be used to add a breakline. |- | youtube_trailer_id || Optionally, specify the ID for a YouTube video to associate with this mod as a preview trailer. The ID is the text after ?v= in a YouTube video URL. |- | requirements || An array of strings specifying other mods which must be installed to use this mod. Each string in the array should match the '''id''' key of the required mod. |- | requirements_names || A parallel array to the '''requirements''' array, which you can use to display more user friendly names for the requirements in the REMIX menu rather than displaying their internal '''id''' string. |- | checksum_override_version || An optional boolean parameter. If false, or omitted, the mod will be considered &quot;updated&quot; if changes are found to any files in the mod's folder. If true, the mod will only be considered &quot;updated&quot; if the value of the '''version''' parameter changes. (''See additional notes in the next section below'') |} An example modinfo.json file contents: <syntaxhighlight lang="json"> { "id": "testmod", "name": "Test Mod", "version": "1.0", "target_game_version": "1.5", "authors": "AndrewFM", "description": "This mod does something interesting, probably!", "youtube_trailer_id": "u-cuf39rK8g", "requirements": ["bestmod", "vrmod"], "requirements_names": ["That Other Mod", "Virtual Reality Support"], "checksum_override_version": false } </syntaxhighlight> In addition to the modinfo.json file, the mod directory can also include a '''thumbnail.png''' image to be displayed in the REMIX menu. This should be an image with 16:9 aspect ratio, recommended to be at least 640x360 pixels large. Additionally, the file size of this thumbnail image should remain below 1 MB. === Checksum Override === Note that the "'''checksum_override_version'''" flag can also be useful during development of your mod when file changes will be frequent. This will suppress the checksum validation and prevent the normal workflow of resolving file changes, merges, and mod conflicts, which can save you time when relaunching the game and/or enabling your mod. However, it is recommended to turn this flag back off before distributing your mod. If you leave it enabled and forget to update your mod's version before distributing the update, it may break your mod for people who already had it installed and enabled, as it will suppress the default update resolution workflow. == Overwriting Files == The contents of the mod folder are a mirror of the StreamingAssets folder. For example, if you wanted your mod to replace the image file at: <pre>      "Assets/StreamingAssets/futile/resources/illustrations/maintitle.png" </pre> with a different image, you would place the new image at: <pre>      "your-mod-folder/futile/resources/illustrations/maintitle.png" </pre> Since the directory structure and file name match one of the original game's files, the game will use the version from your mod directory instead of the original version of the file, whenever your mod is enabled. In some cases files outside the StreamingAssets folder can be modified as well. For example to modify sound effects (Assets/LoadedSoundEffects) your folder structure would be: <pre>      "your-mod-folder/futile/resources/loadedsoundeffects/..." </pre> Or to modify music files (Assets/Music), the structure would be: <pre>      "your-mod-folder/futile/resources/music/..." </pre> Refer to [[Downpour Reference/Modification Files]] for other ways to modify existing files other than completely overwriting their contents, for better mod compatibility. == AssetManager == Whenever referencing any asset files from disk in your code (whether they be files from within your mod's folder, or files within the base game's folders), you should use the static utility functions offered by the AssetManager class. This ensures the file path to the correct version of the file is used based on which mods are enabled or disabled, following the logic above. For example: <pre>AssetManager.ResolveFilePath(&quot;futile/resources/illustrations/maintitle.png&quot;);</pre> This would return the file path to the vanilla maintitle.png file. However, if the example mod described in the previous section were enabled, this instead would return the file path to that mod's overwritten version of maintitle.png. The available utility functions are: {|class="wikitable" ! Method !! Meaning |- | '''ResolveFilePath(path)''' || Return the correct path to the given file based on enabled/disabled mods. |- | '''ResolveDirectory(path)''' || Return the correct path to the given subdirectory based on enabled/disabled mods. |- | '''ListDirectory(path)''' || Returns all unique files contained in all versions of the given subdirectory based on enabled/disabled mods. |- | '''ListDirectory(path, true)''' || Returns all unique subdirectories contained in all versions of the given subdirectory based on enabled/disabled mods. |} To give an example of ListDirectory, consider a hypothetical vanilla directory at: <pre>      "Assets/StreamingAssets/futile/resources/example"<br /> </pre> which contained the files "a.txt", "b.txt", and "c.txt". Then say you created a mod which included the folder: <pre>      "your-mod-folder/futile/resources/example"<br /> </pre> which contained the files "c.txt", and "d.txt". Then when the code below is executed: <pre> AssetManager.ListDirectory("futile/resources/example"); </pre> If your mod is disabled, the files "a.txt" (vanilla), "b.txt" (vanilla), "c.txt" (vanilla) would be returned. If your mod is enabled, the files "a.txt" (vanilla), "b.txt" (vanilla), "c.txt" (modded), "d.txt" (modded) would be returned. 38ba546be254fb6ff4d3984c23af2e19c31063f3 355 354 2022-12-30T19:00:01Z AndrewFM 14 wikitext text/x-wiki Each mod in Downpour is stored as a subfolder inside the &quot;Assets/StreamingAssets/mods&quot; directory. This subfolder contains all metadata, file modifications and overrides, assets, and code modules (DLL files) that define the mod's contents and functionality. == ModInfo JSON == Each mod should have a &quot;modinfo.json&quot; file included in the top level directory of the mod. This JSON file defines the metadata for the mod, mainly the information that will be displayed for that mod within the REMIX menu. The following key-value pairs exist for this JSON file: {|class="wikitable" ! Key !! Meaning |- | id || This is a unique string identifier for this mod. This identifier should never be changed. Recommended to be a lower-case string with no spaces. Other mods will reference this ID to refer to your mod, such as when listing mod requirements. |- | name || This is the title of your mod that will be shown and listed in the REMIX menu. |- | version || This is a string specifying the current version number of your mod. |- | target_game_version || The version number of Rain World this mod was made for. |- | authors || A string listing the authors of the mod. The &lt;LINE&gt; keyword can be used to add a breakline. If the authors string is too long to be displayed directly, it will be converted to a credits roll in the REMIX menu. |- | description || A longer description of the functionality of the mod, to be displayed in the REMIX menu. The &lt;LINE&gt; keyword can be used to add a breakline. |- | youtube_trailer_id || Optionally, specify the ID for a YouTube video to associate with this mod as a preview trailer. The ID is the text after ?v= in a YouTube video URL. |- | requirements || An array of strings specifying other mods which must be installed to use this mod. Each string in the array should match the '''id''' key of the required mod. |- | requirements_names || A parallel array to the '''requirements''' array, which you can use to display more user friendly names for the requirements in the REMIX menu rather than displaying their internal '''id''' string. |- | checksum_override_version || An optional boolean parameter. If false, or omitted, the mod will be considered &quot;updated&quot; if changes are found to any files in the mod's folder. If true, the mod will only be considered &quot;updated&quot; if the value of the '''version''' parameter changes. (''See additional notes in the next section below'') |} An example modinfo.json file contents: <syntaxhighlight lang="json"> { "id": "testmod", "name": "Test Mod", "version": "1.0", "target_game_version": "1.5", "authors": "AndrewFM", "description": "This mod does something interesting, probably!", "youtube_trailer_id": "u-cuf39rK8g", "requirements": ["bestmod", "vrmod"], "requirements_names": ["That Other Mod", "Virtual Reality Support"], "checksum_override_version": false } </syntaxhighlight> In addition to the modinfo.json file, the mod directory can also include a '''thumbnail.png''' image to be displayed in the REMIX menu. This should be an image with 16:9 aspect ratio, recommended to be at least 640x360 pixels large. Additionally, the file size of this thumbnail image should remain below 1 MB. === Checksum Override === Note that the "'''checksum_override_version'''" flag can also be useful during development of your mod when file changes will be frequent. This will suppress the checksum validation and prevent the normal workflow of resolving file changes, merges, and mod conflicts, which can save you time when relaunching the game and/or enabling your mod. However, it is recommended to turn this flag back off before distributing your mod. If you leave it enabled and forget to update your mod's version before distributing the update, it may break your mod for people who already had it installed and enabled, as it will suppress the default update resolution workflow. == Overwriting Files == The contents of the mod folder are a mirror of the StreamingAssets folder. For example, if you wanted your mod to replace the image file at: <pre>      "Assets/StreamingAssets/futile/resources/illustrations/maintitle.png" </pre> with a different image, you would place the new image at: <pre>      "your-mod-folder/futile/resources/illustrations/maintitle.png" </pre> Since the directory structure and file name match one of the original game's files, the game will use the version from your mod directory instead of the original version of the file, whenever your mod is enabled. In some cases files outside the StreamingAssets folder can be modified as well. For example to modify sound effects (Assets/LoadedSoundEffects) your folder structure would be: <pre>      "your-mod-folder/futile/resources/loadedsoundeffects/..." </pre> Or to modify music files (Assets/Music), the structure would be: <pre>      "your-mod-folder/futile/resources/music/..." </pre> Refer to [[Downpour Reference/Modification Files]] for other ways to modify existing files other than completely overwriting their contents, for better mod compatibility. == AssetManager == Whenever referencing any asset files from disk in your code (whether they be files from within your mod's folder, or files within the base game's folders), you should use the static utility functions offered by the AssetManager class. This ensures the file path to the correct version of the file is used based on which mods are enabled or disabled, following the logic above. For example: <pre>AssetManager.ResolveFilePath(&quot;futile/resources/illustrations/maintitle.png&quot;);</pre> This would return the file path to the vanilla maintitle.png file. However, if the example mod described in the previous section were enabled, this instead would return the file path to that mod's overwritten version of maintitle.png. The available utility functions are: {|class="wikitable" ! Method !! Meaning |- | '''ResolveFilePath(path)''' || Return the correct path to the given file based on enabled/disabled mods. |- | '''ResolveDirectory(path)''' || Return the correct path to the given subdirectory based on enabled/disabled mods. |- | '''ListDirectory(path)''' || Returns all unique files contained in all versions of the given subdirectory based on enabled/disabled mods. |- | '''ListDirectory(path, true)''' || Returns all unique subdirectories contained in all versions of the given subdirectory based on enabled/disabled mods. |} To give an example of ListDirectory, consider a hypothetical vanilla directory at: <pre>      "Assets/StreamingAssets/futile/resources/example" </pre> which contained the files "a.txt", "b.txt", and "c.txt". Then say you created a mod which included the folder: <pre>      "your-mod-folder/futile/resources/example" </pre> which contained the files "c.txt", and "d.txt". Then when the code below is executed: <pre> AssetManager.ListDirectory("futile/resources/example"); </pre> If your mod is disabled, the files "a.txt" (vanilla), "b.txt" (vanilla), "c.txt" (vanilla) would be returned. If your mod is enabled, the files "a.txt" (vanilla), "b.txt" (vanilla), "c.txt" (modded), "d.txt" (modded) would be returned. 1bf5ad78e1d5a0cb4b8047b11942984770d5dca1 359 355 2023-01-22T23:33:23Z Alextabitha 44 wikitext text/x-wiki Each mod in Downpour is stored as a subfolder inside the &quot;RainWorld_Data/StreamingAssets/mods&quot; directory. This subfolder contains all metadata, file modifications and overrides, assets, and code modules (DLL files) that define the mod's contents and functionality. == ModInfo JSON == Each mod should have a &quot;modinfo.json&quot; file included in the top level directory of the mod. This JSON file defines the metadata for the mod, mainly the information that will be displayed for that mod within the REMIX menu. The following key-value pairs exist for this JSON file: {|class="wikitable" ! Key !! Meaning |- | id || This is a unique string identifier for this mod. This identifier should never be changed. Recommended to be a lower-case string with no spaces. Other mods will reference this ID to refer to your mod, such as when listing mod requirements. |- | name || This is the title of your mod that will be shown and listed in the REMIX menu. |- | version || This is a string specifying the current version number of your mod. |- | target_game_version || The version number of Rain World this mod was made for. |- | authors || A string listing the authors of the mod. The &lt;LINE&gt; keyword can be used to add a breakline. If the authors string is too long to be displayed directly, it will be converted to a credits roll in the REMIX menu. |- | description || A longer description of the functionality of the mod, to be displayed in the REMIX menu. The &lt;LINE&gt; keyword can be used to add a breakline. |- | youtube_trailer_id || Optionally, specify the ID for a YouTube video to associate with this mod as a preview trailer. The ID is the text after ?v= in a YouTube video URL. |- | requirements || An array of strings specifying other mods which must be installed to use this mod. Each string in the array should match the '''id''' key of the required mod. |- | requirements_names || A parallel array to the '''requirements''' array, which you can use to display more user friendly names for the requirements in the REMIX menu rather than displaying their internal '''id''' string. |- | checksum_override_version || An optional boolean parameter. If false, or omitted, the mod will be considered &quot;updated&quot; if changes are found to any files in the mod's folder. If true, the mod will only be considered &quot;updated&quot; if the value of the '''version''' parameter changes. (''See additional notes in the next section below'') |} An example modinfo.json file contents: <syntaxhighlight lang="json"> { "id": "testmod", "name": "Test Mod", "version": "1.0", "target_game_version": "1.5", "authors": "AndrewFM", "description": "This mod does something interesting, probably!", "youtube_trailer_id": "u-cuf39rK8g", "requirements": ["bestmod", "vrmod"], "requirements_names": ["That Other Mod", "Virtual Reality Support"], "checksum_override_version": false } </syntaxhighlight> In addition to the modinfo.json file, the mod directory can also include a '''thumbnail.png''' image to be displayed in the REMIX menu. This should be an image with 16:9 aspect ratio, recommended to be at least 640x360 pixels large. Additionally, the file size of this thumbnail image should remain below 1 MB. === Checksum Override === Note that the "'''checksum_override_version'''" flag can also be useful during development of your mod when file changes will be frequent. This will suppress the checksum validation and prevent the normal workflow of resolving file changes, merges, and mod conflicts, which can save you time when relaunching the game and/or enabling your mod. However, it is recommended to turn this flag back off before distributing your mod. If you leave it enabled and forget to update your mod's version before distributing the update, it may break your mod for people who already had it installed and enabled, as it will suppress the default update resolution workflow. == Overwriting Files == The contents of the mod folder are a mirror of the StreamingAssets folder. For example, if you wanted your mod to replace the image file at: <pre>      "Assets/StreamingAssets/futile/resources/illustrations/maintitle.png" </pre> with a different image, you would place the new image at: <pre>      "your-mod-folder/futile/resources/illustrations/maintitle.png" </pre> Since the directory structure and file name match one of the original game's files, the game will use the version from your mod directory instead of the original version of the file, whenever your mod is enabled. In some cases files outside the StreamingAssets folder can be modified as well. For example to modify sound effects (Assets/LoadedSoundEffects) your folder structure would be: <pre>      "your-mod-folder/futile/resources/loadedsoundeffects/..." </pre> Or to modify music files (Assets/Music), the structure would be: <pre>      "your-mod-folder/futile/resources/music/..." </pre> Refer to [[Downpour Reference/Modification Files]] for other ways to modify existing files other than completely overwriting their contents, for better mod compatibility. == AssetManager == Whenever referencing any asset files from disk in your code (whether they be files from within your mod's folder, or files within the base game's folders), you should use the static utility functions offered by the AssetManager class. This ensures the file path to the correct version of the file is used based on which mods are enabled or disabled, following the logic above. For example: <pre>AssetManager.ResolveFilePath(&quot;futile/resources/illustrations/maintitle.png&quot;);</pre> This would return the file path to the vanilla maintitle.png file. However, if the example mod described in the previous section were enabled, this instead would return the file path to that mod's overwritten version of maintitle.png. The available utility functions are: {|class="wikitable" ! Method !! Meaning |- | '''ResolveFilePath(path)''' || Return the correct path to the given file based on enabled/disabled mods. |- | '''ResolveDirectory(path)''' || Return the correct path to the given subdirectory based on enabled/disabled mods. |- | '''ListDirectory(path)''' || Returns all unique files contained in all versions of the given subdirectory based on enabled/disabled mods. |- | '''ListDirectory(path, true)''' || Returns all unique subdirectories contained in all versions of the given subdirectory based on enabled/disabled mods. |} To give an example of ListDirectory, consider a hypothetical vanilla directory at: <pre>      "Assets/StreamingAssets/futile/resources/example" </pre> which contained the files "a.txt", "b.txt", and "c.txt". Then say you created a mod which included the folder: <pre>      "your-mod-folder/futile/resources/example" </pre> which contained the files "c.txt", and "d.txt". Then when the code below is executed: <pre> AssetManager.ListDirectory("futile/resources/example"); </pre> If your mod is disabled, the files "a.txt" (vanilla), "b.txt" (vanilla), "c.txt" (vanilla) would be returned. If your mod is enabled, the files "a.txt" (vanilla), "b.txt" (vanilla), "c.txt" (modded), "d.txt" (modded) would be returned. d665cbef09ab02c532b324c18335b6f214551dea File:shortcuts yes.png 6 167 344 2022-10-16T20:46:52Z Jevmen 13 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:shortcuts no.png 6 168 345 2022-10-16T20:48:43Z Jevmen 13 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 Level Editor 0 86 346 179 2022-10-16T21:00:46Z Jevmen 13 wikitext text/x-wiki {{Cleanup}} == The Official Level Editor == [[File:editorFront.png|400px|thumb|right]] The Rain World level editor is a powerful tool that allows the creation of new rooms for the game, and editing existing rooms. It is the same editor the developers used to make all of the rooms for the base game. It takes specially formatted spritesheets and a number of programmed effects and outputs png files that the engine interprets in 3D (as well as an accompanying text file which contains collision and gameplay info). You can download the level editor from [https://ln.sync.com/dl/db7b0cf70/nebg7d6b-qg7gjua7-gjdi94jn-xuvivhw3/view/default/8384962820004 here.] There is also the Community Editor, which is a community-made edit of the original editor, with new features, bugfixes, and better ease of use. There is also Drizzle, a community made level renderer that's hardware accelerated. In the future it intends to replace the existing level editors. === Basic Features Overview === Once you've followed the on-screen instructions for either creating or opening a level, you are presented with the dashboard/preview screen. From here, you can switch between the different editors, load or save your level, and export it for use in-game. The preview presented here requires being manually updated whenever changes are made or when you first open a level. Pressing "1" at any point will bring you back to this screen so you can save your level or switch to a different editor. It's often best to start by modifying the dimensions of the room to your liking using the level size button before beginning to edit. You can change this at any time, but because you set the dimensions manually rather than visually, making changes later is more difficult and poses the risk of accidentally deleting a portion of your room if you aren't careful. From the dashboard you can switch to the Geometry Editor (for defining the level geometry and collision), the Tile Editor (for customizing the tiles and assets that make up the geometry created in the geometry editor), the Effects Editor (for adding procedural effects like erosion or slime, as well as things like plants or chains), the Light Editor (for customizing the light and shadow in your room), or the Prop Editor (for adding additional hand placed props and decals like graffiti). === Controls Overview === ==== View controls (numpad): ==== These are used for every editor view except the Camera and Environment editor to scroll around the screen. Notice, numlock must be turned on for these controls to have any effect. {| class="wikitable" |+ |- ! Key(s) !! Function |- | 8,2,4,6 || Moves view |- | 1 (hold) || Increases view scroll speed. |- | 3 (hold) || Increases view scroll speed even more. |- | 9 (hold) || Allow the view to move outside the boundaries of the level. |} ==== Menu keybinds (Number row): ==== These act as hotkeys to quickly switch between different editor views. These can be used in any editor view as well. {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | 1 || Main menu |- | 2 || Geometry |- | 3 || Tiles |- | 4 || Cameras |- | 5 || Light |- | 6 || Room size |} === Level Settings === ==== Level Size ==== This is where you change how big the level is. You can set the entire level size, and border tiles. Border tiles are padding around the room, mainly for resolutions that are larger than 4:3 It's recomended not to go under the defaults, or your final render will be cut off. ==== Default Medium ==== This determines if you can fall outside of the level or not, death pits still work the same either way however. ==== Light Type ==== The light type can either be set to '''ON''' which will use what you have done in the Light Editor, or '''OFF''' which paints everything in shadow. ==== Seed ==== This is the arrow on the fourth row of bars, which determines what seed the level will use. The seed determines random tile and prop placement, along with how effects are generated. === Rendering === ==== Prioritize Cam ==== This determines what camera will be rendered first, before starting from the beginning. Very useful for re-rendering a specific screen. ==== Text Output ==== This outputs a .txt of the level's geometry, usable in-game. ==== Render Level ==== This renders the screens ==== Mass Render ==== This will render every level in the selected folder. === Editors === <tabber> |-|Geometry Editor= == Geometry Editor == [[File: geoEditor.png|400px|thumb|right]] The Geometry Editor is the first stop for the creation of new rooms. In the Geometry Editor, you define the gameplay and collision information of your room, such as the placement of vertical and horizontal bars, shortcuts, room entrances, creature dens, and garbage worm placement. (to connect your room to other rooms), and a number of other gameplay relevant elements. === Controls === {| class="wikitable" |+ Geometry editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | Arrow keys || Primary cursor scroll through toolbox. If mouse over the toolbox, mouse moves cursor instead. |- | Mouse || Primary cursor movement. |- | LMB || Primary cursor use current tool. |- | Q (hold) || Secondary cursor scroll through toolbox. |- | E,S,D,F || Secondary cursor movement. |- | W || Secondary cursor use current tool. |} As an experimental feature, the developers implemented a second cursor and control scheme to allow two users to edit a room simultaneously (with the second user entirely on the keyboard). While this ended up being a little used feature (as far as we are aware), it is still implemented in the current editor (represented by the grey cursor). == Toolbox == {| class="wikitable" |+ Level Editor Geo Tools |- | Inverse || Flips the currently selected tile between walls, and air. |- | Paint Walls || Paints solid tiles. |- | Paint Air || Paints non-solid tiles. |- | Make Slope || Paints a slope, these can only be placed inside corners, and as the edges of larger solids. |- | Make Floor || Paints thin platforms that you can stand on, but also hold down to fall through. |- | Rect Wall || Paints solid tiles in a rectangle. Click two points to set the rectangle's dimensions and paint. |- | Rect Air || Same as above, except for non-solid tiles. |- | Worm Grass || Placed above solid ground to spawn worm grass tendrils. The number placed together to the left and right decides the height of the grass. |- | Crack Terrain || Renders as a roughly cracked fissure through the material painted on it in the tile editor. Slugcat can crawl through these tunnels. An example in the vanilla game is in the western temple styled area of the subterranean. Where there are fissures to travel beneath certain stone statues. |- | Horizontal Beam || Climbable pole. Slugcat can only climb these on layer 1. |- | Vertical Beam || Same as above, except in the other direction. |- | Glass Wall || Paints invisible solid walls. |- | Waterfall || Will cause a waterfall to appear in game, with this tile at the top of it. |} {| class="wikitable" |+ Level Editor Item and Batfly Tools |- | Place Rock || A Rock will spawn at this location with a 60% chance. |- | Place Spear ||A Spear will spawn at this location with a 60% chance. |- | Spawn Fly || Does nothing. |- | Forbid Fly Chains || Prevents bat flies from hanging together in specific locations to rest. |- | Hive || Places a bat fly hive. Bat flies can use these to quickly travel to different parts of a room. |} === Short Cuts and Entrances === [[File: shortcuts_yes.png|260px|thumb|Examples of working shortcuts]] [[File: shortcuts_no.png|260px|right|thumb|Examples of broken shortcuts]] {| class="wikitable" |+ Level Editor Shortcut Tools |- | Short Cut Entrance || Places the entrance of a short cut into the room, these must be fully surrounded by ground except from the entrance side and the exit will always be aiming in the oposite direction of the entrance. When placed on the floor, both players and creatures will fall into them, so its advised to always put a platform in the entrance instead of air in these cases. |- | Short Cut || Places a short cut's travel dot. These can connect two short cut entrances together or connect into a specific entrance or den variation. They can also have no destination, in which case the shortcut entrance will simply be blocked. Short cut dots can cross with each other in a + pattern and each path will always continue forwards. |- | Dragon Den || Places a creature den. These hold the creature assigned to that den in the region's World File. |- | Entrance || Used to connect with another room. These can be used by Slugcat and most creatures to travel across a region, the 2 rooms connected by this entrance are determined in the region's World File. |- | Scavenger Hole || Allows scavengers to spawn or travel to this room as they wander through a region. Since scavenger use offscreen dens, all the Scavenger Holes will share the same pool of scavengers. |- | Whack-A-Mole-Hole || Allows creatures to travel arround a room by "teleporting" between these holes. There is no limit to how many holes can be placed in the same room and they are all connected with each other. When a creature enters one of these holes and selects a new destination there is a short period of time in which the shortcut segment glows, so they are often used without Short Cut dots. |- | "G" Garbage Worm den || Unlike the rest of dens, its not attached to a short cut entrance. Instead they are simply placed in the ground tile where we want the Garbage Worm to spawn. |} Short cuts and their connections to the various kinds of entrances in Rain World have specific needs! Improperly making the short cut can lead to crashes, or odd behavior in game. This gif presents several examples of properly linked short cuts. A short cut dot is not required between the short cut's entrance, and the den or door it is connecting to. However, the shortcut must show as an arrow toward the den or door for the link to it to be proper. The short cut entrance also requires walls surrounding it on all sides, with the exception of the side you will enter it from. Connecting two short cut entrances to each other with dots will connect them as a tunnel between the two. The various other den and entrance types will decide how enemies interact with the entrance. Dens are used for most normal creatures. Scavenger require their unique entrance type to enter the room properly without using normal doors. ( They will not be able to leave the OFFSCREEN room of the region if there are no scavenger doors at all in the region! ) Garbage worms require a unique door due to their AI's behavior, and cannot use normal dens, nore can enemies enter their dens. Finally the Whack-A-Mole holes are used by creatures to warp from various short cuts around the room. The images on the right also display the bare minimum needed for short cut entrances to function, and example doors in all directions. === Layer Info === {| class="wikitable" |+ Level Editor Layer and Misc Tools |- | Copy Backwards || Copies a rectangle of tiles on the current layer to the next layer. This does not wrap around back to layer 1 if you are on layer 3. |- | Work Layer || Changes layers from 1 to 3 and then back to 1. |- | Clear All || Selects a rectangle that resets all tiles inside it, on all layers, back to open air. |- | Toggle Mirror || Turns on and off a mirror tile painting mode. What you do on one side of the mirror will be copied on the other. |- | Move Mirror || Allows you to move the location of the Mirror. |- | Move Level || Moves the whole level in a certain direction. Place the mouse cursor outside the level, then use the arrow keys to move the level in the direction you want. It will not work if your mouse is inside the level as using the arrow keys will swap to another tool. |- | Empty || Does nothing. Good to set as your tool if you have to tab out, as it does nothing. |} Rain World levels consist of 3 layers, each representing a different depth. This layer info is represented visually through the color of tiles, and you can switch between editing on different layers with the work layer tool in the bottom left of the tool panel. Layer 1 draws in full black, layer 2 draws in green, and layer 3 draws in red. These colors will blend if multiple layers are drawn on top of each other. Layer 1 is the foreground, and any filled tiles on this layer will have collision. This is the base layer you define for the sake of gameplay, as any air here is space you can traverse. Layer 2 is the midground, which you can imagine as the back wall of your room. Wall climbing creatures also interact with this. Layer 3 is the extreme background, behind the back wall of the room (for placing distant objects or giving the room a section of open sky). Nothing interacts with this at all. Note: The tile editor defines the visual tiles and props that make up this geometry, so in order to place solid objects in the tile editor (on any layer), those tiles need to be filled here in the geometry editor. Even though the mid-ground and background do not provide any collision geometry, in order to place solid props on those layers the tiles need to be filled here in the geometry editor. Similarly, some props can only be placed on air on the layers (like fences). === Tips and Tricks === - Many of the gameplay features require that they be placed within the margins of your room (represented by the white border). An entrance or creature den placed outside of your margins will render your room un-enterable at best, and crash the game at worst. Short Cut Entrances and Short Cuts can be placed outside the level boundary just fine, however. - Border tiles are tiles that can't be interacted with, and are there for looks only. The room will copy the last tile from the border forever in that direction so be careful with your geometry, or you'll be able to walk out of bounds through "solid" walls or stand in the air. - Because the tool panel loops around from top to bottom and left to right, when editing the base geometry (walls and air) it's faster to use the arrow keys to go up to reach the work layer tool to swap layers than to cycle through the whole list to reach them. Also, the rectangular wall and air tools will let you edit large chunks of your level much faster than going tile by tile. - Because the layers move with a parallax effect, it's often necessary to extend elements on your background layer behind your other layers, otherwise the camera angle will sometimes let you see a gap to the left or right of a background wall and the layer in front of it (for example). It can be just a few tiles extended, unless you have tiles infront that are transparent and reveal behind it. |-|Tile Editor= Full article here [[Tile Editor]]. {| class="wikitable" |+ Tile editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Select tile category |- | W,S || Select tile in current category |- | LMB || Place tile under cursor |- | RMB || Erase tile under cursor |- | F (hold) || Use a 3x3 brush for materials |- | V (hold) || Use a 5x5 brush for materials |- | Tab+x+c || Clears all tiles |- | L || Change active layer (1, 2, 3, loop back to 1) |- | E || Sets default material of the room to the currently selected material |- | F (hold) || Enables force placing selected tile (ignoring geometry, erasing colliding tiles) |- | G (hold) || Enables force placing selected tile (forcing appropriate geometry for the tile, erasing colliding tiles) |- | Q || "Eyedropper" (selects tile/material hovered over) |} |-|Effect Editor= Full article here [[Effects Editor]]. {| class="wikitable" |+ Effect library keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Select effect category |- | W,S || Select effect in current category |- | E || Switches to editing applied effects |- | Space || Adds selected effect to the stack |} {| class="wikitable" |+ Applied effect keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,S || Scroll through the effect stack |- | N || Switch to effect library |- | Space || Edit selected effect in the stack |} Effect editing: {| class="wikitable" |+ Effect editing keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Scroll through options in the effect's menu |- | W,S || Changes the current effect's menu |- | Space || Activates selected option in the effect's menu |- | LMB || Paints effect in the level |- | RMB || Erases effect in the level |- | R || Brush size up |- | F || Brush size down |- | E || Switch to effect stack |- | N || Switch to effect library |} |-|Camera Editor= Full article here Camera Editor. N - New camera, spawns held by mouse E - grab a camera if none is held D - Delete held camera P - Place held camera |-|Light editor= Full article here [[Light Editor]]. {| class="wikitable" |+ Light editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,A,S,D || Scale current light shape |- | Q,E || Rotate current light shape |- | Z || Toggle between drawing and erasing light |- | LMB || Paint light |- | RMB (hold) || Rotate light shape in direction of mouse ( does not paint it.) |- | R,F || Scroll through light shape library |- | J,L || Change angle of light source |- | I,K || Change distance of light source |} |-|Prop Editor= Full article here [[Prop Editor]]. {| class="wikitable" |+ Prop editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A, D || Changes prop library's category |- | W, S || Scrolls through props in current category |- | LMB || Place current prop |- | V (hold) || LMB erases highlighted prop |- | Q,E || Rotate prop left and right |- | Space (hold) || Speed up rotation |- | Y,G,H,J || Stretch prop |- | T || Reset prop stretching |- | R || reset stretching, and rotation |- | Y, H || (on wire/tube props) increases or decreases prop's physics node count. Less means more taught, more means more loose |- | X || Pause wire/tube physics |- | Tab+X+C || clear all props |- | B || Click mouse left to set the highlighted prop as the currently selected prop |- | L || Change layer |- | RMB || Cycle depth in current layer (10 sublevels). |- | Space + RMB || Cycle depth in current layer, reverse direction. |- | U,I,O,P (hold) || Freeform stretch by one of the corners (U - top right, I - bottom right, O - bottom left, and P - top left.) |- | K || resets freeform stretching. |- | N || Switches to editing properties menu of the prop. Things like forcing certain graffiti to be drawn instead of a random one. |- | M (hold) || LMB opens properties of an already placed prop instead of placing a prop (same menu as above) |- | Z || Changes prop color |- | F + LMB/RMB || Changes between prop variants. This only applies to certain props. |} |-|Environment Editor= {| class="wikitable" |+ Environment editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | L || Set water level to mouse pointer |- | F || Toggles between drawing water above the first layer or below it. |- | W || Toggle water on level |} </tabber> == Crash Avoidance and Editor Quirks == Due to the editor being extremely user unfriendly, you are likely to run into various crashes without warning. This is a list of various things to avoid doing. === Crashes: === Do not switch to editing applied effects in the Effects Editor when there are none. The switch will be invisible, and attempting to use the space bar to select something from there will crash the Level Editor. Some effects have very specific conditions and cause issues when rendering, Effects include: Thick Roots, and Shadow Plants. these ones can be okayed through until it renders.) Be sure to remove tiles from parts of a room that will be removed if you resize the room to cut those areas out, those tiles are still recorded, and will crash renders instantly. props are the exact same as above Never render with no cameras. It will crash. Always move the prop menu into an actual category when you open it, it keeps the last menu used, and crashes if you select any entry that is not a real prop. (EX: it will have the effects menu, or tile menu.) If you are using the Mirrored tile placer, in the geometry editor. Placing poles, with the other side of the mirrored brush being outside of the room, will crash the editor. === Quirks: === The main menu is a mess when you return from using the Light Editor or the Environment Editor. Just change to any other editor (geometry or tiles, and back to main menu) to clean it. This is not a crash, but will help prevent confusion if you know to expect this. To use the Move and Move Mirror tools in the editor, you must first select them, and then move your mouse outside of the room itself, before it will respond to your inputs. Usually you will only need to put your mouse over the editor, but in larger rooms, this is often an issue, as the room is "behind" the menu, and thus only changes tool selection. The editor still receives inputs if you only tab out using alt-tab. When viewing another window, it's important to always minimize the editor, because there are many things that can go wrong if you're randomly clicking in the editor. (Requires more confirmation) The screen during rendering should usually show the map being rendered, but it may not. In the task manager, The Rain World Editor is under the tab Adobe Projector. Sometimes the reason it is not showing is a second application called "Print driver host for applications". Closing the application seems to fix the issue. The window for the application may be too big to fit on screen, and cannot be fixed since reaching the top bar or right clicking cannot be accessed to move the window. === Demo and Tutorial Videos === Region Developer Kaeporo created a tutorial for creating levels in and out of the level editor: {{#ev:youtube|YQ0DO-fmPCE|||||urlargs=""}} Mod community member Sacretis also put together a demonstration video, this time covering the creation of a room from scratch to visual polish (massively sped up for the sake of time): {{#ev:youtube|sEE3X1izaJA|||||urlargs=""}} f6cad1dc615d87ba26fada5341b5793d7e636a60 347 346 2022-10-17T20:43:28Z Jevmen 13 wikitext text/x-wiki {{Cleanup}} == The Official Level Editor == [[File:editorFront.png|400px|thumb|right]] The Rain World level editor is a powerful tool that allows the creation of new rooms for the game, and editing existing rooms. It is the same editor the developers used to make all of the rooms for the base game. It takes specially formatted spritesheets and a number of programmed effects and outputs png files that the engine interprets in 3D (as well as an accompanying text file which contains collision and gameplay info). You can download the level editor from [https://ln.sync.com/dl/db7b0cf70/nebg7d6b-qg7gjua7-gjdi94jn-xuvivhw3/view/default/8384962820004 here.] There is also the Community Editor, which is a community-made edit of the original editor, with new features, bugfixes, and better ease of use. There is also Drizzle, a community made level renderer that's hardware accelerated. In the future it intends to replace the existing level editors. === Basic Features Overview === Once you've followed the on-screen instructions for either creating or opening a level, you are presented with the dashboard/preview screen. From here, you can switch between the different editors, load or save your level, and export it for use in-game. The preview presented here requires being manually updated whenever changes are made or when you first open a level. Pressing "1" at any point will bring you back to this screen so you can save your level or switch to a different editor. It's often best to start by modifying the dimensions of the room to your liking using the level size button before beginning to edit. You can change this at any time, but because you set the dimensions manually rather than visually, making changes later is more difficult and poses the risk of accidentally deleting a portion of your room if you aren't careful. From the dashboard you can switch to the Geometry Editor (for defining the level geometry and collision), the Tile Editor (for customizing the tiles and assets that make up the geometry created in the geometry editor), the Effects Editor (for adding procedural effects like erosion or slime, as well as things like plants or chains), the Light Editor (for customizing the light and shadow in your room), or the Prop Editor (for adding additional hand placed props and decals like graffiti). === Controls Overview === ==== View controls (numpad): ==== These are used for every editor view except the Camera and Environment editor to scroll around the screen. Notice, numlock must be turned on for these controls to have any effect. {| class="wikitable" |+ |- ! Key(s) !! Function |- | 8,2,4,6 || Moves view |- | 1 (hold) || Increases view scroll speed. |- | 3 (hold) || Increases view scroll speed even more. |- | 9 (hold) || Allow the view to move outside the boundaries of the level. |} ==== Menu keybinds (Number row): ==== These act as hotkeys to quickly switch between different editor views. These can be used in any editor view as well. {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | 1 || Main menu |- | 2 || Geometry |- | 3 || Tiles |- | 4 || Cameras |- | 5 || Light |- | 6 || Room size |} === Level Settings === ==== Level Size ==== This is where you change how big the level is. You can set the entire level size, and border tiles. Border tiles are padding around the room, mainly for resolutions that are larger than 4:3 It's recomended not to go under the defaults, or your final render will be cut off. ==== Default Medium ==== This determines if you can fall outside of the level or not, death pits still work the same either way however. ==== Light Type ==== The light type can either be set to '''ON''' which will use what you have done in the Light Editor, or '''OFF''' which paints everything in shadow. ==== Seed ==== This is the arrow on the fourth row of bars, which determines what seed the level will use. The seed determines random tile and prop placement, along with how effects are generated. === Rendering === ==== Prioritize Cam ==== This determines what camera will be rendered first, before starting from the beginning. Very useful for re-rendering a specific screen. ==== Text Output ==== This outputs a .txt of the level's geometry, usable in-game. ==== Render Level ==== This renders the screens ==== Mass Render ==== This will render every level in the selected folder. === Editors === <tabber> |-|Geometry Editor= == Geometry Editor == [[File: geoEditor.png|400px|thumb|right]] The Geometry Editor is the first stop for the creation of new rooms. In the Geometry Editor, you define the gameplay and collision information of your room, such as the placement of vertical and horizontal bars, shortcuts, room entrances, creature dens, and garbage worm placement. (to connect your room to other rooms), and a number of other gameplay relevant elements. === Controls === {| class="wikitable" |+ Geometry editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | Arrow keys || Primary cursor scroll through toolbox. If mouse over the toolbox, mouse moves cursor instead. |- | Mouse || Primary cursor movement. |- | LMB || Primary cursor use current tool. |- | Q (hold) || Secondary cursor scroll through toolbox. |- | E,S,D,F || Secondary cursor movement. |- | W || Secondary cursor use current tool. |} As an experimental feature, the developers implemented a second cursor and control scheme to allow two users to edit a room simultaneously (with the second user entirely on the keyboard). While this ended up being a little used feature (as far as we are aware), it is still implemented in the current editor (represented by the grey cursor). == Toolbox == {| class="wikitable" |+ Level Editor Geo Tools |- | Inverse || Flips the currently selected tile between walls, and air. |- | Paint Walls || Paints solid tiles. |- | Paint Air || Paints non-solid tiles. |- | Make Slope || Paints a slope, these can only be placed inside corners, and as the edges of larger solids. |- | Make Floor || Paints thin platforms that you can stand on, but also hold down to fall through. |- | Rect Wall || Paints solid tiles in a rectangle. Click two points to set the rectangle's dimensions and paint. |- | Rect Air || Same as above, except for non-solid tiles. |- | Worm Grass || Placed above solid ground to spawn worm grass tendrils. The number placed together to the left and right decides the height of the grass. |- | Crack Terrain || Renders as a roughly cracked fissure through the material painted on it in the tile editor. Slugcat can crawl through these tunnels. An example in the vanilla game is in the western temple styled area of the subterranean. Where there are fissures to travel beneath certain stone statues. |- | Horizontal Beam || Climbable pole. Slugcat can only climb these on layer 1. |- | Vertical Beam || Same as above, except in the other direction. |- | Glass Wall || Paints invisible solid walls. |- | Waterfall || Will cause a waterfall to appear in game, with this tile at the top of it. |} {| class="wikitable" |+ Level Editor Item and Batfly Tools |- | Place Rock || A Rock will spawn at this location with a 60% chance. |- | Place Spear ||A Spear will spawn at this location with a 60% chance. |- | Spawn Fly || Does nothing. |- | Forbid Fly Chains || Prevents bat flies from hanging together in specific locations to rest. |- | Hive || Places a bat fly hive. Bat flies can use these to quickly travel to different parts of a room. |} === Short Cuts and Entrances === [[File: shortcuts_yes.png|270px|thumb|Examples of working shortcuts]] [[File: shortcuts_no.png|270px|right|thumb|Examples of broken shortcuts]] {| class="wikitable" |+ Level Editor Shortcut Tools |- | Short Cut Entrance || Places the entrance of a short cut into the room, these must be fully surrounded by ground except from the entrance side and the exit will always be aiming in the oposite direction of the entrance. When placed on the floor, both players and creatures will fall into them, so its advised to always put a platform in the entrance instead of air in these cases. |- | Short Cut || Places a short cut's travel dot. These can connect two short cut entrances together or connect into a specific entrance or den variation. They can also have no destination, in which case the shortcut entrance will simply be blocked. Short cut dots can cross with each other in a + pattern and each path will always continue forwards. |- | Dragon Den || Places a creature den. These hold the creature assigned to that den in the region's World File. Creatures can move to the closest den if they cant return to their own. |- | Entrance || Used to connect with another room. These can be used by Slugcat and most creatures to travel across a region, the 2 rooms connected by this entrance are determined in the region's World File. |- | Scavenger Hole || Allows scavengers to spawn or travel to this room as they wander through a region. Since scavenger use offscreen dens, all the Scavenger Holes will share the same pool of scavengers. |- | Whack-A-Mole-Hole || Allows creatures to travel arround a room by "teleporting" between these holes. There is no limit to how many holes can be placed in the same room and they are all connected with each other. When a creature enters one of these holes and selects a new destination there is a short period of time in which the shortcut segment glows, so they are often used without Short Cut dots. |- | "G" Garbage Worm den || Unlike the rest of dens, its not attached to a short cut entrance. Instead they are simply placed in the ground tile where we want the Garbage Worm to spawn. |} A short cut dot is not required between the short cut's entrance and the den or door it's connecting to. However, the shortcut must show as an arrow toward the den or door for the link to it to be proper. Short cuts and their connections to the various kinds of entrances in Rain World have specific needs! Improperly making the short cut can lead to crashes, or odd behavior in game. A list of common mistakes include: -Short cuts going outside of the level bounds, anything out of the white frame won't be loaded in game. -Short cut entrances placed directly on the surface. -Short cut entrances with short cut dots on any side which isn't the opposite to the entrance. -Creature dens or room entrances randomly floating in the room disconnected from everything. -Placing Garbage Worm dens connected to an entrance like the other dens. === Layer Info === {| class="wikitable" |+ Level Editor Layer and Misc Tools |- | Copy Backwards || Copies a rectangle of tiles on the current layer to the next layer. This does not wrap around back to layer 1 if you are on layer 3. |- | Work Layer || Changes layers from 1 to 3 and then back to 1. |- | Clear All || Selects a rectangle that resets all tiles inside it, on all layers, back to open air. |- | Toggle Mirror || Turns on and off a mirror tile painting mode. What you do on one side of the mirror will be copied on the other. |- | Move Mirror || Allows you to move the location of the Mirror. |- | Move Level || Moves the whole level in a certain direction. Place the mouse cursor outside the level, then use the arrow keys to move the level in the direction you want. It will not work if your mouse is inside the level as using the arrow keys will swap to another tool. |- | Empty || Does nothing. Good to set as your tool if you have to tab out, as it does nothing. |} Rain World levels consist of 3 layers, each representing a different depth. This layer info is represented visually through the color of tiles, and you can switch between editing on different layers with the work layer tool in the bottom left of the tool panel. Layer 1 draws in full black, layer 2 draws in green, and layer 3 draws in red. These colors will blend if multiple layers are drawn on top of each other. Layer 1 is the foreground, and any filled tiles on this layer will have collision. This is the base layer you define for the sake of gameplay, as any air here is space you can traverse. Layer 2 is the midground, which you can imagine as the back wall of your room. Wall climbing creatures also interact with this. Layer 3 is the extreme background, behind the back wall of the room (for placing distant objects or giving the room a section of open sky). Nothing interacts with this at all. Note: The tile editor defines the visual tiles and props that make up this geometry, so in order to place solid objects in the tile editor (on any layer), those tiles need to be filled here in the geometry editor. Even though the mid-ground and background do not provide any collision geometry, in order to place solid props on those layers the tiles need to be filled here in the geometry editor. Similarly, some props can only be placed on air on the layers (like fences). === Tips and Tricks === - Many of the gameplay features require that they be placed within the margins of your room (represented by the white border). An entrance or creature den placed outside of your margins will render your room un-enterable at best, and crash the game at worst. Short Cut Entrances and Short Cuts can be placed outside the level boundary just fine, however. - Border tiles are tiles that can't be interacted with, and are there for looks only. The room will copy the last tile from the border forever in that direction so be careful with your geometry, or you'll be able to walk out of bounds through "solid" walls or stand in the air. - Because the tool panel loops around from top to bottom and left to right, when editing the base geometry (walls and air) it's faster to use the arrow keys to go up to reach the work layer tool to swap layers than to cycle through the whole list to reach them. Also, the rectangular wall and air tools will let you edit large chunks of your level much faster than going tile by tile. - Because the layers move with a parallax effect, it's often necessary to extend elements on your background layer behind your other layers, otherwise the camera angle will sometimes let you see a gap to the left or right of a background wall and the layer in front of it (for example). It can be just a few tiles extended, unless you have tiles infront that are transparent and reveal behind it. |-|Tile Editor= Full article here [[Tile Editor]]. {| class="wikitable" |+ Tile editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Select tile category |- | W,S || Select tile in current category |- | LMB || Place tile under cursor |- | RMB || Erase tile under cursor |- | F (hold) || Use a 3x3 brush for materials |- | V (hold) || Use a 5x5 brush for materials |- | Tab+x+c || Clears all tiles |- | L || Change active layer (1, 2, 3, loop back to 1) |- | E || Sets default material of the room to the currently selected material |- | F (hold) || Enables force placing selected tile (ignoring geometry, erasing colliding tiles) |- | G (hold) || Enables force placing selected tile (forcing appropriate geometry for the tile, erasing colliding tiles) |- | Q || "Eyedropper" (selects tile/material hovered over) |} |-|Effect Editor= Full article here [[Effects Editor]]. {| class="wikitable" |+ Effect library keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Select effect category |- | W,S || Select effect in current category |- | E || Switches to editing applied effects |- | Space || Adds selected effect to the stack |} {| class="wikitable" |+ Applied effect keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,S || Scroll through the effect stack |- | N || Switch to effect library |- | Space || Edit selected effect in the stack |} Effect editing: {| class="wikitable" |+ Effect editing keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Scroll through options in the effect's menu |- | W,S || Changes the current effect's menu |- | Space || Activates selected option in the effect's menu |- | LMB || Paints effect in the level |- | RMB || Erases effect in the level |- | R || Brush size up |- | F || Brush size down |- | E || Switch to effect stack |- | N || Switch to effect library |} |-|Camera Editor= Full article here Camera Editor. N - New camera, spawns held by mouse E - grab a camera if none is held D - Delete held camera P - Place held camera |-|Light editor= Full article here [[Light Editor]]. {| class="wikitable" |+ Light editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,A,S,D || Scale current light shape |- | Q,E || Rotate current light shape |- | Z || Toggle between drawing and erasing light |- | LMB || Paint light |- | RMB (hold) || Rotate light shape in direction of mouse ( does not paint it.) |- | R,F || Scroll through light shape library |- | J,L || Change angle of light source |- | I,K || Change distance of light source |} |-|Prop Editor= Full article here [[Prop Editor]]. {| class="wikitable" |+ Prop editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A, D || Changes prop library's category |- | W, S || Scrolls through props in current category |- | LMB || Place current prop |- | V (hold) || LMB erases highlighted prop |- | Q,E || Rotate prop left and right |- | Space (hold) || Speed up rotation |- | Y,G,H,J || Stretch prop |- | T || Reset prop stretching |- | R || reset stretching, and rotation |- | Y, H || (on wire/tube props) increases or decreases prop's physics node count. Less means more taught, more means more loose |- | X || Pause wire/tube physics |- | Tab+X+C || clear all props |- | B || Click mouse left to set the highlighted prop as the currently selected prop |- | L || Change layer |- | RMB || Cycle depth in current layer (10 sublevels). |- | Space + RMB || Cycle depth in current layer, reverse direction. |- | U,I,O,P (hold) || Freeform stretch by one of the corners (U - top right, I - bottom right, O - bottom left, and P - top left.) |- | K || resets freeform stretching. |- | N || Switches to editing properties menu of the prop. Things like forcing certain graffiti to be drawn instead of a random one. |- | M (hold) || LMB opens properties of an already placed prop instead of placing a prop (same menu as above) |- | Z || Changes prop color |- | F + LMB/RMB || Changes between prop variants. This only applies to certain props. |} |-|Environment Editor= {| class="wikitable" |+ Environment editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | L || Set water level to mouse pointer |- | F || Toggles between drawing water above the first layer or below it. |- | W || Toggle water on level |} </tabber> == Crash Avoidance and Editor Quirks == Due to the editor being extremely user unfriendly, you are likely to run into various crashes without warning. This is a list of various things to avoid doing. === Crashes: === Do not switch to editing applied effects in the Effects Editor when there are none. The switch will be invisible, and attempting to use the space bar to select something from there will crash the Level Editor. Some effects have very specific conditions and cause issues when rendering, Effects include: Thick Roots, and Shadow Plants. these ones can be okayed through until it renders.) Be sure to remove tiles from parts of a room that will be removed if you resize the room to cut those areas out, those tiles are still recorded, and will crash renders instantly. props are the exact same as above Never render with no cameras. It will crash. Always move the prop menu into an actual category when you open it, it keeps the last menu used, and crashes if you select any entry that is not a real prop. (EX: it will have the effects menu, or tile menu.) If you are using the Mirrored tile placer, in the geometry editor. Placing poles, with the other side of the mirrored brush being outside of the room, will crash the editor. === Quirks: === The main menu is a mess when you return from using the Light Editor or the Environment Editor. Just change to any other editor (geometry or tiles, and back to main menu) to clean it. This is not a crash, but will help prevent confusion if you know to expect this. To use the Move and Move Mirror tools in the editor, you must first select them, and then move your mouse outside of the room itself, before it will respond to your inputs. Usually you will only need to put your mouse over the editor, but in larger rooms, this is often an issue, as the room is "behind" the menu, and thus only changes tool selection. The editor still receives inputs if you only tab out using alt-tab. When viewing another window, it's important to always minimize the editor, because there are many things that can go wrong if you're randomly clicking in the editor. (Requires more confirmation) The screen during rendering should usually show the map being rendered, but it may not. In the task manager, The Rain World Editor is under the tab Adobe Projector. Sometimes the reason it is not showing is a second application called "Print driver host for applications". Closing the application seems to fix the issue. The window for the application may be too big to fit on screen, and cannot be fixed since reaching the top bar or right clicking cannot be accessed to move the window. === Demo and Tutorial Videos === Region Developer Kaeporo created a tutorial for creating levels in and out of the level editor: {{#ev:youtube|YQ0DO-fmPCE|||||urlargs=""}} Mod community member Sacretis also put together a demonstration video, this time covering the creation of a room from scratch to visual polish (massively sped up for the sake of time): {{#ev:youtube|sEE3X1izaJA|||||urlargs=""}} c8f3cf0fd4d1a7ad00f43919b00800103c1c1a79 348 347 2022-10-17T21:35:40Z Jevmen 13 wikitext text/x-wiki {{Cleanup}} == The Official Level Editor == [[File:editorFront.png|400px|thumb|right]] The Rain World level editor is a powerful tool that allows the creation of new rooms for the game, and editing existing rooms. It is the same editor the developers used to make all of the rooms for the base game. It takes specially formatted spritesheets and a number of programmed effects and outputs png files that the engine interprets in 3D (as well as an accompanying text file which contains collision and gameplay info). You can download the level editor from [https://ln.sync.com/dl/db7b0cf70/nebg7d6b-qg7gjua7-gjdi94jn-xuvivhw3/view/default/8384962820004 here.] There is also the Community Editor, which is a community-made edit of the original editor, with new features, bugfixes, and better ease of use. There is also Drizzle, a community made level renderer that's hardware accelerated. In the future it intends to replace the existing level editors. === Basic Features Overview === Once you've followed the on-screen instructions for either creating or opening a level, you are presented with the dashboard/preview screen. From here, you can switch between the different editors, load or save your level, and export it for use in-game. The preview presented here requires being manually updated whenever changes are made or when you first open a level. Pressing "1" at any point will bring you back to this screen so you can save your level or switch to a different editor. It's often best to start by modifying the dimensions of the room to your liking using the level size button before beginning to edit. You can change this at any time, but because you set the dimensions manually rather than visually, making changes later is more difficult and poses the risk of accidentally deleting a portion of your room if you aren't careful. From the dashboard you can switch to the Geometry Editor (for defining the level geometry and collision), the Tile Editor (for customizing the tiles and assets that make up the geometry created in the geometry editor), the Effects Editor (for adding procedural effects like erosion or slime, as well as things like plants or chains), the Light Editor (for customizing the light and shadow in your room), or the Prop Editor (for adding additional hand placed props and decals like graffiti). === Controls Overview === ==== View controls (numpad): ==== These are used for every editor view except the Camera and Environment editor to scroll around the screen. Notice, numlock must be turned on for these controls to have any effect. {| class="wikitable" |+ |- ! Key(s) !! Function |- | 8,2,4,6 || Moves view |- | 1 (hold) || Increases view scroll speed. |- | 3 (hold) || Increases view scroll speed even more. |- | 9 (hold) || Allow the view to move outside the boundaries of the level. |} ==== Menu keybinds (Number row): ==== These act as hotkeys to quickly switch between different editor views. These can be used in any editor view as well. {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | 1 || Main menu |- | 2 || Geometry |- | 3 || Tiles |- | 4 || Cameras |- | 5 || Light |- | 6 || Room size |} === Level Settings === ==== Level Size ==== This is where you change how big the level is. You can set the entire level size, and border tiles. Border tiles are padding around the room, mainly for resolutions that are larger than 4:3 It's recomended not to go under the defaults, or your final render will be cut off. ==== Default Medium ==== This determines if you can fall outside of the level or not, death pits still work the same either way however. ==== Light Type ==== The light type can either be set to '''ON''' which will use what you have done in the Light Editor, or '''OFF''' which paints everything in shadow. ==== Seed ==== This is the arrow on the fourth row of bars, which determines what seed the level will use. The seed determines random tile and prop placement, along with how effects are generated. === Rendering === ==== Prioritize Cam ==== This determines what camera will be rendered first, before starting from the beginning. Very useful for re-rendering a specific screen. ==== Text Output ==== This outputs a .txt of the level's geometry, usable in-game. ==== Render Level ==== This renders the screens ==== Mass Render ==== This will render every level in the selected folder. === Editors === <tabber> |-|Geometry Editor= == Geometry Editor == [[File: geoEditor.png|400px|thumb|right]] The Geometry Editor is the first stop for the creation of new rooms. In the Geometry Editor, you define the gameplay and collision information of your room, such as the placement of vertical and horizontal bars, shortcuts, room entrances, creature dens, and garbage worm placement. (to connect your room to other rooms), and a number of other gameplay relevant elements. === Controls === {| class="wikitable" |+ Geometry editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | Arrow keys || Primary cursor scroll through toolbox. If mouse over the toolbox, mouse moves cursor instead. |- | Mouse || Primary cursor movement. |- | LMB || Primary cursor use current tool. |- | Q (hold) || Secondary cursor scroll through toolbox. |- | E,S,D,F || Secondary cursor movement. |- | W || Secondary cursor use current tool. |} As an experimental feature, the developers implemented a second cursor and control scheme to allow two users to edit a room simultaneously (with the second user entirely on the keyboard). While this ended up being a little used feature (as far as we are aware), it is still implemented in the current editor (represented by the grey cursor). == Toolbox == {| class="wikitable" |+ Level Editor Geo Tools |- | Inverse || Flips the currently selected tile between walls, and air. |- | Paint Walls || Paints solid tiles. |- | Paint Air || Paints non-solid tiles. |- | Make Slope || Paints a slope, these can only be placed inside corners, and as the edges of larger solids. |- | Make Floor || Paints thin platforms that you can stand on, but also hold down to fall through. |- | Rect Wall || Paints solid tiles in a rectangle. Click two points to set the rectangle's dimensions and paint. |- | Rect Air || Same as above, except for non-solid tiles. |- | Worm Grass || Placed above solid ground to spawn worm grass tendrils. The number placed together to the left and right decides the height of the grass. |- | Crack Terrain || Renders as a roughly cracked fissure through the material painted on it in the tile editor. Slugcat can crawl through these tunnels. An example in the vanilla game is in the western temple styled area of the subterranean. Where there are fissures to travel beneath certain stone statues. |- | Horizontal Beam || Climbable pole. Slugcat can only climb these on layer 1. |- | Vertical Beam || Same as above, except in the other direction. |- | Glass Wall || Paints invisible solid walls. |- | Waterfall || Will cause a waterfall to appear in game, with this tile at the top of it. |} {| class="wikitable" |+ Level Editor Item and Batfly Tools |- | Place Rock || A Rock will spawn at this location with a 60% chance. |- | Place Spear ||A Spear will spawn at this location with a 60% chance. |- | Spawn Fly || Does nothing. |- | Forbid Fly Chains || Prevents bat flies from hanging together in specific locations to rest. |- | Hive || Places a bat fly hive. Bat flies can use these to quickly travel to different parts of a room. |} === Short Cuts and Entrances === [[File: shortcuts_yes.png|270px|thumb|Examples of working shortcuts]] [[File: shortcuts_no.png|270px|right|thumb|Examples of broken shortcuts]] {| class="wikitable" |+ Level Editor Shortcut Tools |- | Short Cut Entrance || Places the entrance of a short cut into the room, these must be fully surrounded by ground except from the entrance side and the exit will always be aiming in the oposite direction of the entrance. When placed on the floor, both players and creatures will fall into them, so its advised to always put a platform in the entrance instead of air in these cases. |- | Short Cut || Places a short cut's travel dot. These can connect two short cut entrances together or connect into a specific entrance or den variation. They can also have no destination, in which case the shortcut entrance will simply be blocked. Short cut dots can cross with each other in a + pattern and each path will always continue forwards. |- | Dragon Den || Places a creature den. These hold the creature assigned to that den in the region's World File. Creatures can move to the closest den if they cant return to their own. |- | Entrance || Used to connect with another room. These can be used by Slugcat and most creatures to travel across a region, the 2 rooms connected by this entrance are determined in the region's World File. |- | Scavenger Hole || Allows scavengers to spawn or travel to this room as they wander through a region. Since scavenger use offscreen dens, all the Scavenger Holes will share the same pool of scavengers. |- | Whack-A-Mole-Hole || Allows creatures to travel arround a room by "teleporting" between these holes. There is no limit to how many holes can be placed in the same room and they are all connected with each other. When a creature enters one of these holes and selects a new destination there is a short period of time in which the shortcut segment glows, so they are often used without Short Cut dots. |- | "G" Garbage Worm den || Unlike the rest of dens, its not attached to a short cut entrance. Instead they are simply placed in the ground tile where we want the Garbage Worm to spawn. |} A short cut dot is not required between the short cut's entrance and the den or door it's connecting to. However, the shortcut must show as an arrow toward the den or door for the link to it to be proper. Short cuts and their connections to the various kinds of entrances in Rain World have specific needs! Improperly making the short cut can lead to crashes, or odd behavior in game. A list of common mistakes include: * Short cuts going outside of the level bounds, anything out of the white frame won't be loaded in game. * Short cut entrances placed directly on the surface. * Short cut entrances with short cut dots on any side which isn't the opposite to the entrance. * Creature dens or room entrances randomly floating in the room disconnected from everything. * Placing Garbage Worm dens connected to an entrance like the other dens. === Layer Info === {| class="wikitable" |+ Level Editor Layer and Misc Tools |- | Copy Backwards || Copies a rectangle of tiles on the current layer to the next layer. This does not wrap around back to layer 1 if you are on layer 3. |- | Work Layer || Changes layers from 1 to 3 and then back to 1. |- | Clear All || Selects a rectangle that resets all tiles inside it, on all layers, back to open air. |- | Toggle Mirror || Turns on and off a mirror tile painting mode. What you do on one side of the mirror will be copied on the other. |- | Move Mirror || Allows you to move the location of the Mirror. |- | Move Level || Moves the whole level in a certain direction. Place the mouse cursor outside the level, then use the arrow keys to move the level in the direction you want. It will not work if your mouse is inside the level as using the arrow keys will swap to another tool. |- | Empty || Does nothing. Good to set as your tool if you have to tab out, as it does nothing. |} Rain World levels consist of 3 layers, each representing a different depth. This layer info is represented visually through the color of tiles, and you can switch between editing on different layers with the work layer tool in the bottom left of the tool panel. Layer 1 draws in full black, layer 2 draws in green, and layer 3 draws in red. These colors will blend if multiple layers are drawn on top of each other. Layer 1 is the foreground, and any filled tiles on this layer will have collision. This is the base layer you define for the sake of gameplay, as any air here is space you can traverse. Layer 2 is the midground, which you can imagine as the back wall of your room. Wall climbing creatures also interact with this. Layer 3 is the extreme background, behind the back wall of the room (for placing distant objects or giving the room a section of open sky). Nothing interacts with this at all. Note: The tile editor defines the visual tiles and props that make up this geometry, so in order to place solid objects in the tile editor (on any layer), those tiles need to be filled here in the geometry editor. Even though the mid-ground and background do not provide any collision geometry, in order to place solid props on those layers the tiles need to be filled here in the geometry editor. Similarly, some props can only be placed on air on the layers (like fences). === Tips and Tricks === - Many of the gameplay features require that they be placed within the margins of your room (represented by the white border). An entrance or creature den placed outside of your margins will render your room un-enterable at best, and crash the game at worst. Short Cut Entrances and Short Cuts can be placed outside the level boundary just fine, however. - Border tiles are tiles that can't be interacted with, and are there for looks only. The room will copy the last tile from the border forever in that direction so be careful with your geometry, or you'll be able to walk out of bounds through "solid" walls or stand in the air. - Because the tool panel loops around from top to bottom and left to right, when editing the base geometry (walls and air) it's faster to use the arrow keys to go up to reach the work layer tool to swap layers than to cycle through the whole list to reach them. Also, the rectangular wall and air tools will let you edit large chunks of your level much faster than going tile by tile. - Because the layers move with a parallax effect, it's often necessary to extend elements on your background layer behind your other layers, otherwise the camera angle will sometimes let you see a gap to the left or right of a background wall and the layer in front of it (for example). It can be just a few tiles extended, unless you have tiles infront that are transparent and reveal behind it. |-|Tile Editor= Full article here [[Tile Editor]]. {| class="wikitable" |+ Tile editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Select tile category |- | W,S || Select tile in current category |- | LMB || Place tile under cursor |- | RMB || Erase tile under cursor |- | F (hold) || Use a 3x3 brush for materials |- | V (hold) || Use a 5x5 brush for materials |- | Tab+x+c || Clears all tiles |- | L || Change active layer (1, 2, 3, loop back to 1) |- | E || Sets default material of the room to the currently selected material |- | F (hold) || Enables force placing selected tile (ignoring geometry, erasing colliding tiles) |- | G (hold) || Enables force placing selected tile (forcing appropriate geometry for the tile, erasing colliding tiles) |- | Q || "Eyedropper" (selects tile/material hovered over) |} |-|Effect Editor= Full article here [[Effects Editor]]. {| class="wikitable" |+ Effect library keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Select effect category |- | W,S || Select effect in current category |- | E || Switches to editing applied effects |- | Space || Adds selected effect to the stack |} {| class="wikitable" |+ Applied effect keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,S || Scroll through the effect stack |- | N || Switch to effect library |- | Space || Edit selected effect in the stack |} Effect editing: {| class="wikitable" |+ Effect editing keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Scroll through options in the effect's menu |- | W,S || Changes the current effect's menu |- | Space || Activates selected option in the effect's menu |- | LMB || Paints effect in the level |- | RMB || Erases effect in the level |- | R || Brush size up |- | F || Brush size down |- | E || Switch to effect stack |- | N || Switch to effect library |} |-|Camera Editor= Full article here Camera Editor. N - New camera, spawns held by mouse E - grab a camera if none is held D - Delete held camera P - Place held camera |-|Light editor= Full article here [[Light Editor]]. {| class="wikitable" |+ Light editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,A,S,D || Scale current light shape |- | Q,E || Rotate current light shape |- | Z || Toggle between drawing and erasing light |- | LMB || Paint light |- | RMB (hold) || Rotate light shape in direction of mouse ( does not paint it.) |- | R,F || Scroll through light shape library |- | J,L || Change angle of light source |- | I,K || Change distance of light source |} |-|Prop Editor= Full article here [[Prop Editor]]. {| class="wikitable" |+ Prop editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A, D || Changes prop library's category |- | W, S || Scrolls through props in current category |- | LMB || Place current prop |- | V (hold) || LMB erases highlighted prop |- | Q,E || Rotate prop left and right |- | Space (hold) || Speed up rotation |- | Y,G,H,J || Stretch prop |- | T || Reset prop stretching |- | R || reset stretching, and rotation |- | Y, H || (on wire/tube props) increases or decreases prop's physics node count. Less means more taught, more means more loose |- | X || Pause wire/tube physics |- | Tab+X+C || clear all props |- | B || Click mouse left to set the highlighted prop as the currently selected prop |- | L || Change layer |- | RMB || Cycle depth in current layer (10 sublevels). |- | Space + RMB || Cycle depth in current layer, reverse direction. |- | U,I,O,P (hold) || Freeform stretch by one of the corners (U - top right, I - bottom right, O - bottom left, and P - top left.) |- | K || resets freeform stretching. |- | N || Switches to editing properties menu of the prop. Things like forcing certain graffiti to be drawn instead of a random one. |- | M (hold) || LMB opens properties of an already placed prop instead of placing a prop (same menu as above) |- | Z || Changes prop color |- | F + LMB/RMB || Changes between prop variants. This only applies to certain props. |} |-|Environment Editor= {| class="wikitable" |+ Environment editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | L || Set water level to mouse pointer |- | F || Toggles between drawing water above the first layer or below it. |- | W || Toggle water on level |} </tabber> == Crash Avoidance and Editor Quirks == Due to the editor being extremely user unfriendly, you are likely to run into various crashes without warning. This is a list of various things to avoid doing. === Crashes: === Do not switch to editing applied effects in the Effects Editor when there are none. The switch will be invisible, and attempting to use the space bar to select something from there will crash the Level Editor. Some effects have very specific conditions and cause issues when rendering, Effects include: Thick Roots, and Shadow Plants. these ones can be okayed through until it renders.) Be sure to remove tiles from parts of a room that will be removed if you resize the room to cut those areas out, those tiles are still recorded, and will crash renders instantly. props are the exact same as above Never render with no cameras. It will crash. Always move the prop menu into an actual category when you open it, it keeps the last menu used, and crashes if you select any entry that is not a real prop. (EX: it will have the effects menu, or tile menu.) If you are using the Mirrored tile placer, in the geometry editor. Placing poles, with the other side of the mirrored brush being outside of the room, will crash the editor. === Quirks: === The main menu is a mess when you return from using the Light Editor or the Environment Editor. Just change to any other editor (geometry or tiles, and back to main menu) to clean it. This is not a crash, but will help prevent confusion if you know to expect this. To use the Move and Move Mirror tools in the editor, you must first select them, and then move your mouse outside of the room itself, before it will respond to your inputs. Usually you will only need to put your mouse over the editor, but in larger rooms, this is often an issue, as the room is "behind" the menu, and thus only changes tool selection. The editor still receives inputs if you only tab out using alt-tab. When viewing another window, it's important to always minimize the editor, because there are many things that can go wrong if you're randomly clicking in the editor. (Requires more confirmation) The screen during rendering should usually show the map being rendered, but it may not. In the task manager, The Rain World Editor is under the tab Adobe Projector. Sometimes the reason it is not showing is a second application called "Print driver host for applications". Closing the application seems to fix the issue. The window for the application may be too big to fit on screen, and cannot be fixed since reaching the top bar or right clicking cannot be accessed to move the window. === Demo and Tutorial Videos === Region Developer Kaeporo created a tutorial for creating levels in and out of the level editor: {{#ev:youtube|YQ0DO-fmPCE|||||urlargs=""}} Mod community member Sacretis also put together a demonstration video, this time covering the creation of a room from scratch to visual polish (massively sped up for the sake of time): {{#ev:youtube|sEE3X1izaJA|||||urlargs=""}} ca3bf42e7d3a76e722b5ac8bc54c20fd8b5b9b0d World File Format 0 114 349 235 2022-11-10T20:54:13Z Bro748 31 /* Creature Spawns */ wikitext text/x-wiki {{Cleanup}} [[File:regionFormat.png|thumb|right|alt=regionFormat|regionFormat]] This page describes worldfile format for RW regions. The world_XX.txt file is present in every region Rain World loads, and determines various room settings such as their pipe connections, the spawns of enemies, and specific flags like shelters and gates. NOTE: Creature spawns for the region are generated when you first enter it on a save. Changing room connections or creature spawns in WORLD_XX after that corrupts save data. '''Reset your saveslot or revert your save to before you entered to avoid bugs'''. == Comments == Worldfile format supports comments: if a line starts with double slash (<code>//</code>), it is ignored entirely. == Room Connections == Room connections section is bounded by <code>ROOMS</code> and <code>END ROOMS</code> tags. These control which pipe entrance leads to what room, and vice versa. Unique room flags that specify certain attributes about the room (such as if it is a shelter or a gate room) are set here as well. The format is as follows: <syntaxhighlight lang="">ROOM : door0, door1, door2, etc : FLAG </syntaxhighlight> === Examples === A standard room with two room-connecting pipes. These will form the bulk of your region. <syntaxhighlight lang="">TR_T07 : TR_T01, TR_P02 </syntaxhighlight> A standard room, with five doors. However, pipes 1, 2 and 3 have no connection. Each pipe inside a room has a specific number starting from 0. These can be viewed using the [[Dev Tools]]' map tab, or by entering the room with dev tools enabled and pressing M. <syntaxhighlight lang="">TR_W19 : TR_L05, DISCONNECTED, DISCONNECTED, DISCONNECTED, TR_W18 </syntaxhighlight> A shelter. These rooms will often be copied from other regions when you are first learning how to make a region. All vanilla save rooms have a single door. <syntaxhighlight lang="">TR_S01 : TR_P01 : SHELTER </syntaxhighlight> A region gate. Doors on the other side of the gate are set to DISCONNECTED. They will automatically be shown as connected doors at runtime. If you need to show a save room door specifically on the other side of the gate, you can use the ExitSymbolShelter object, in the dev tool’s object tab to change the door symbols as required. <syntaxhighlight lang="">GATE_SS_TR : DISCONNECTED, TR_L07 : GATE </syntaxhighlight> A swarm room allows batflies to spawn in the room, as long as the map contains bat nests. If the room has bat nests but is not marked as a swarm room, those nests will always be inactive. The dev tools map tab provides the options needed to control where they will migrate and rooms they will avoid. <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> A scavenger outpost. Use in conjunction with ScavengerOutpost placedObject to create a scavenger toll. <syntaxhighlight lang="">SU_C02 : SU_A45, SU_A07 : SCAVOUTPOST </syntaxhighlight> === Understanding door connections === [[File:regionFormatConnection.png|thumb|none|alt=regionFormatConnection|regionFormatConnection]] For a door to be properly connected, both ends must point to each other using valid doors. For this example, both rooms will have two doors. Door0 will be on the left, and door1 on the right. Door indices are decided specifically for your room, so be sure to check in game how your doors have been assigned by the [[Level Editor]]. The DT Map tab can also be used to see the links between doors. As in the picture to the right. Properly connected doors will show both lines pointing to the set door on the other end. Doors with incorrect links will point off to the bottom right <!--(A disconnected door will also do this,)--> <!--do fucking what--> and a door connected to another room, but that room has no door back (or lacks enough doors!) will point to the center of the room on the map tab page. <syntaxhighlight lang=""> RG_ROOM1 : DISCONNECTED, RG_ROOM2 </syntaxhighlight> <syntaxhighlight lang=""> RG_ROOM2: RG_ROOM1 </syntaxhighlight> Room1 will have its right hand door connected to Room2. Because of this, we need to use DISCONNECTED as a placeholder for its left hand door, door0. Then set door1 to connect to Room2 Room2 will connect to Room1 using door0. Due to this, we do not need to define the right hand door. It will assume it to be disconnected. === Room Tags === Room tags assign certain properties to rooms depending on what the tag is. Tags are assigned like <syntaxhighlight lang=""> [ROOM] : [CONNECTIONS] : [TAG] </syntaxhighlight> Example: <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> {|class="wikitable" !width="18%"| '''<u>Tag</u>''' !width="81%"| '''<u>Function</u>''' |- | SHELTER | Makes the room a shelter. When there are multiple pipes in the room: the animated door is placed at the bottom right most pipe. |- | GATE | Makes the room a gate. Entrances on the other side of the gate are set to DISCONNECTED, and are shown automatically to be connected. |- | SWARMROOM | Allows batflies to be spawned from batfly hives. |- | PERF_HEAVY | Causes the room to be abstractized quicker when player is not inside, can reduce offscreen performance toll of very large rooms. |- | SCAVOUTPOST | Makes the room into a scavenger outpost. Scavs will spawn here and only let you pass if you have a pearl. The exact outpost location is set by the “ScavengerOutpost” devtools object. |- | SCAVTRADER | Spawns a scavenger merchant into the room. Will trade items with you. The merchant is controlled by the “TradeOutpost” devtools object. |} === Important quirks to rooms and doors === When setting up your region, be sure that you always use your region’s prefix to help each room have a unique name. If not, Rain World will treat repeated names as being other rooms, and even re-use rooms from other region folders entirely. If you don’t use your region prefix, changes made with devtools can also wind up getting saved to unexpected places. To avoid these problems, always prefix your room with its region code, and give them unique names. Multiple pipes in a room may all go to the same room. However, these will all act like a single pipe, and you will not be able to set the specific destination pipes. There are no cases in vanilla Rain World where multiple pipes in the current room lead to the same next room. They will all lead to separate rooms. For example, if you had four pipes leading from one room to another. you would need to create a minimum of three unique rooms for each of the other pipes to act as an interconnection. == Creature Spawns == Creature spawn data section is bounded by <code>CREATURES</code> and <code>END CREATURES</code> tags. Rain World only creates creature spawns when you enter a region for the first time on a save<!--, or after an excessive number of cycles has passed--><!--never heard of it before, may be bogus ~thalber-->. {|class="wikitable" !align="center" width="12%"| '''Lizards''' !align="center" width="25%"| '''Insects''' !align="center" width="13%"| '''Amphibians''' !align="center" width="18%"| '''Flying''' !align="center" width="16%"| '''Plants''' !align="center" width="12%"| '''Other''' |- |align="center"| Pink |align="center"| Spider |align="center"| Salamander |align="center"| CicadaA |align="center"| PoleMimic, Mimic* |align="center"| Scavenger |- |align="center"| Green |align="center"| Small Centipede |align="center"| Leech |align="center"| CicadaB |align="center"| Tentacle, TentaclePlant* |align="center"| Lantern Mouse, Mouse* |- |align="center"| Blue |align="center"| Centipede, Centi, Cent* |align="center"| SeaLeech |align="center"| Vulture |align="center"| |align="center"| Worm, Garbage Worm* |- |align="center"| Yellow |align="center"| Red Centipede, RedCenti, RedCentipede* |align="center"| JetFish, Jetfish* |align="center"| KingVulture, King Vulture* |align="center"| |align="center"| Miros, MirosBird* |- |align="center"| White |align="center"| DropBug, Dropbug, DropWig, Dropwig* |align="center"| Snail |align="center"| Needle, Needle Worm* |align="center"| |align="center"| Tube, TubeWorm* |- |align="center"| Black |align="center"| BigSpider |align="center"| Lev, Leviathan |align="center"| SmallNeedleWorm |align="center"| |align="center"| Bro, BroLongLegs* |- |align="center"| Cyan |align="center"| SpitterSpider |align="center"| |align="center"| Centiwing |align="center"| |align="center"| Daddy, DaddyLongLegs* |- |align="center"| Red |align="center"| EggBug, Eggbug* |align="center"| |align="center"| Cicada** |align="center"| |align="center"| |} (*) Interchangeable names (**) Switches between CicadaA and CicadaB) <syntaxhighlight lang=""> //Creature spawns can be specific to a certain character. (0, 1) makes something appear for monk and survivor, (2) only for hunter (character filter)ROOM : PipeNumber-Creature-{optional flags}-Count </syntaxhighlight> === Creature Flags === <!--'Flags' is a bad name for this, I think 'tags' would be more appropriate ~bro--> Creature flags set certain properties of the creature. Any flag can be written to any creature, but it will be ignored if they are not one of the following matches: Lizards may have the {mean:x.x} flag, with x.x representing a number ranging from 0.0 to 1.0 (eg, {Mean:0.6}) This makes the lizard act more aggressively Centipedes may have the {x.x} flag, being a number ranging from 0.0 to 1.0 (eg, {0.7}) This sets the centipede size, with 0.0 being a Small Centipede and 1.0 being an Overgrown Centipede Pole plants may have the {xx} flag, being any non-negative integer (eg, {15}) This sets the length of the pole plant in tiles === Examples === A single green lizard, spawning from pipe 2, on all difficulties. <syntaxhighlight lang=""> SU_A10 : 2-Green </syntaxhighlight> A single red lizard, spawning from pipe 3, on Hunter only. <syntaxhighlight lang=""> (2)SU_A10 : 3-Red </syntaxhighlight> A hoard of 5 yellow lizards spawning from pipe 1, on Monk only. <syntaxhighlight lang=""> (1)SU_A10 : 1-Yellow-5 </syntaxhighlight> A Daddy longlegs spawning from pipe 4, but only on easy and normal difficulties. <syntaxhighlight lang=""> (0,1)SU_A10 : 4-Daddy </syntaxhighlight> A very angry white lizard that spawns from pipe 3, on all difficulties. <syntaxhighlight lang=""> SU_A10 : 3-White-{Mean:0.9} </syntaxhighlight> Some enemies require a unique room known as OFFSCREEN. These enemies use special doors that are automatically added to your level to move between rooms. These include vultures, scavengers, leviathans, and miros birds. This example spawns two off screen vultures. <syntaxhighlight lang=""> OFFSCREEN : 0-Vulture-2 </syntaxhighlight> <!--Enemy flags still apply to offscreen enemies. This will spawn a very aggressive KingVulture that will rarely leave the screen if it spots slugcat, but only on Hunter. <syntaxhighlight lang=""> (2)OFFSCREEN : 0-KingVulture-{Mean:1} </syntaxhighlight> <span id="important-quirks-to-creatures"></span> --><!--King Vultures do not read the info set in their 'flags' ~Bro--> === Important quirks === Enemies may be set to spawn from the same nest pipes. However, do not be surprised if they somehow kill each other offscreen very quickly if you do this. A daddy long legs may have no problems consuming an entire hoard of yellow lizards for example. Enemies will often drag you back to their home nest pipes, but may also choose other pipes they like, even in different rooms. During the end of a cycle, almost every enemy will rush to a nearby nest, if they spawned from it or not. Many creatures that would not intuitively appear to nest in pipes, likely does so, you just never reach them before they spawn in game, or their pipes are well hidden. A direct example of this, is that wandering daddy longlegs spawn from pipes, and return to their pipes before the end of a cycle. This includes the daddies inside Five Pebbles, which makes the area significantly easier once the cycle timer has counted down entirely. It is important to understand various enemy interactions to help you build a cohesive and believable ecosystem for an area. Sandbox mode can help you learn which creature is where on the food chain. As well as looking at the interactions of creatures in other regions. Some creatures have very specific requirements for rooms they inhabit. A very game breaking example, is that big spiders and spitting spiders require the ability to reach every wall in a room in some fashion. By pole, or by invisible ceilings out of the camera. If they cannot, the game will lag very badly due to the spider’s failed pathfinding. Some creatures have a heavier performance impact on the game then others. <!--Sandbox mode can help you learn these, as it will show a notice that “too many of this creature will impact performance” when you begin to place too many.--> <!-- the arena threshold seems somewhat arbitrary in present day--> An example is that more then 4 daddy long legs on screen will often lead to lag. Unfortunate development gets around this problem by using the “stuckDaddy” object, as these daddies do not run wandering path finding checks. All creature types can be configured using the dev tool’s map editor to prefer, avoid, stay or be forbidden inside certain rooms while wandering, using Attraction tool. These spawn entries are simply where they will be created from when the player first enters a region. <span id="the-lineage-system"></span> === The Lineage System === Enemy nests may also be configured to use the lineage system. After being killed, this allows a creature to roll a dice at the end of a cycle, and in a certain percent, respawn as its next entry in the lineage. Due to the format however, you cannot decide how many enemies can spawn from the pipe. So a green lizard cannot turn into a hoard of 3 yellow lizards. Only a single yellow lizard. Enemy flags, and difficulty filters still work however. The format is as follows: <syntaxhighlight lang=""> LINEAGE : ROOM : PIPE : STARTENEMY-PERCENT, NEXTENEMY-PERCENT, FINALENEMY-0 </syntaxhighlight> PERCENT is a value between 0 and 1, and is the percent chance that the enemy will move onto its next form. You may have as many forms as you need. However, it is important to ALWAYS mark the last enemy in the lineage with a 0 percent chance to move on. Rain World will crash the moment it attempts to move to the next enemy in a lineage from the last. ==== Examples ==== A green lizard that spawns from pipe 2, that turns into a blue, and then into a red. With a 5% chance each time. <syntaxhighlight lang=""> LINEAGE : SU_B08 : 2 : Green-0.05, Blue-0.05, Red-0 </syntaxhighlight> A poleplant, with a specific height of 10 blocks, and spawning from pipe 3. That has a 10% chance to turn into a monster kelp <syntaxhighlight lang=""> LINEAGE : SU_A02 : 3 : Mimic-{10}-0.1, TentaclePlant-0 </syntaxhighlight> A empty pipe 3, that has a 1% chance to turn into a monster kelp. <syntaxhighlight lang=""> LINEAGE : SU_B02 : 3 : NONE-0.01, TentaclePlant-0 </syntaxhighlight> Lineage applies to offscreen creatures, as well as difficulties! This example from chimney canopy has a 20% chance to turn a vulture into a king vulture after being killed, but only on normal difficulty. <syntaxhighlight lang=""> (0)LINEAGE : OFFSCREEN : 0 : Vulture-0.2, KingVulture-0 </syntaxhighlight> == Bat Migration Blockages == Bat migration blockages section is bounded by <code>BAT MIGRATION BLOCKAGES</code> and <code>END BAT MIGRATION BLOCKAGES</code> tags. These are used specifically to prevent bat flies from entering a room, or pathing through the region to rooms on the other side of it. These are rarely used. However the room directly after the tutorial area in outskirts is set to be one. The format is simply to list each room line by line between the two tags. There are no unique flags. For the example in Outskirts, bat flies cannot enter room SU_A22 because it is between the tags: <syntaxhighlight lang="">BAT MIGRATION BLOCKAGES SU_A22 END BAT MIGRATION BLOCKAGES </syntaxhighlight> [[Category:Content Mods]] 3797c32c923528b75634e066b11fc3b2a835216a Downpour Reference/File Formats 0 147 350 283 2022-12-17T21:32:08Z AndrewFM 14 Updating conditional links example wikitext text/x-wiki Certain file formats have marginally changed in Downpour with the most common difference being that many things are now stored by value rather than by index. Some files also support new fields / attributes / parameters for new features. Most of these changes are optional and the files will still be parsed properly via backwards compatibility if still stored as indices, but updating may improve mod compatibility for the future. == locks.txt == This is the same, but " : SWAPMAPSYMBOL" can be added to the end of a line to swap the order that the two gate symbols appear on the in-game mini-map. == egates.txt == <code>egates.txt</code> is a new file in the same folder as locks.txt. Placing a gate room name as a new line in this file makes the gate an electric gate. == properties.txt == * Slugcats listed under Broken Shelters should be listed by name rather than index. (<code>Broken Shelters: <u>2</u>: SL_S11''"</code> -&gt; <code>Broken Shelters: <u>Red</u>: SL_S11</code>) * <code>blackSalamanderChance</code> is a new parameter that can be used to change the probability of salamanders in this region spawning as their dark variant. (Default: <code>blackSalamanderChance: 0.33</code>) * <code>corruptionEffectColor</code> is a new parameter than can be used to change the effect color of corruption objects and BLL creatures in the region. (Default <code>corruptionEffectColor: 0.0,0.0,1.0</code>) * <code>corruptionEyeColor</code> is a new parameter than can be used to change the eye color of corruption objects and BLL creatures in the region. (Default <code>corruptionEffectColor: 0.0,0.0,1.0</code>) * <code>kelpColor</code> is a new parameter that can be used to change the color of kelp creatures in the region. * <code>albinos</code> is a new parameter that can make relevant creautres spawn as their albino variants in a region. (Default <code>albinos: false</code>) * <code>waterColorOverride</code> is a new parameter that can change the color that water appears on the in-game minimap for the region. (Default <code>waterColorOverride: 0.05,0.05,0.8</code>) * <code>earlyCycleChance</code> is a new parameter that can set the probability of a pre-cycle event occurring at the start of a cycle in the region. (MSC only) * <code>earlyCycleFloodChance</code> is a new parameter that can set the probability of partial region flooding occuring during a pre-cycle event in this region. (MSC only) * <code>scavsDelayInitialMin</code> is a new parameter that sets the minimum time in ticks before a kill squad will be sent after a disliked player after entering this region. (default 4200) * <code>scavsDelayInitialMax</code> is a new parameter that sets the maximum time in ticks before a kill squad will be sent after a disliked player after entering this region. (default 8200) * <code>scavsDelayRepeatMin</code> is a new parameter that sets the minimum time in ticks before a support squad will be sent to a liked player after entering this region. (default 1100) * <code>scavsDelayRepeatMax</code> is a new parameter that sets the maximum time in ticks before a support squad will be sent to a liked player after entering this region. (default 1700) * Room_Attr lists attractiveness with <code>Neutral,Forbidden,Avoid,Like,Stay</code> instead of <code>0,1,2,3,4</code> respectively -- but it is optional to update this. Properties files can be suffixed by a slugcat name to make a region properties file exclusive to a specific slugcat campaign. (ie: properties-red.txt would apply the properties only while playing as Hunter). == map_xx.txt/map_xx.png == Map files can be suffixed by a slugcat name to make a map render exclusive to a specific slugcat campaign. (ie: <code>map_xx-red.png</code>) == displayname.txt == '''This file is required'''. This file contains a single line that contains the name of the region. This exists in the same folder as the properties / world_xx files. Display name files can also be provided that are suffixed by a slugcat name to change the name of the region for specific slugcat campaigns. (ie: <code>displayname-red.txt</code>) == world_xx.txt == Slugcat-specific spawn lines should be listed by name rather than index. (<code>(<u>0,1</u>)CC_A07 : 3-Mimic-{18}</code> -&gt; <code>(<u>White,Yellow</u>)CC_A07 : 3-Mimic-{18}</code>). A new "CONDITIONAL LINKS"/"END CONDITIONAL LINKS" section can be added before the "ROOMS"/"END ROOMS" section in the file to specify room connection changes that apply to specific slugcats. There are three types of conditional link lines: * <code>SLUGCAT : HIDEROOM : ROOM</code> - This excludes the given room from the region when playing as the specified slugcat(s). ** (Example) <code>White,Yellow : HIDEROOM : SU_A99</code> * <code>SLUGCAT : EXCLUSIVEROOM : ROOM</code> - This includes the given room in the region only when playing as the selected slugcat(s). ** (Example) <code>White,Yellow : EXCLUSIVEROOM : SU_A99</code> * <code>SLUGCAT : TARGET_ROOM : TARGET_CONNECTION_ROOM : NEW_CONNECTION_ROOM</code> - This changes the given room connection in the target room to now connect to a different specified room while playing as the specified slugcat(s). For the last conditional link type, the "TARGET_CONNECTION_ROOM" is specified by the room name for named room connections, or with a number to target a DISCONNECTED connection (1 for the first DISCONNECTED pipe in the room, 2 for the second DISCONNECTED, etc). To give an example for this last conditional link line type, imagine the following line existed in the ROOMS/END ROOMS section of the file: <pre>GW_A10 : GW_D01, GW_A07, GW_C06 GW_A11 : GW_B01, GW_D04, DISCONNECTED, GW_F07, DISCONNECTED</pre> Then the following conditional links lines: <pre>White,Yellow : GW_A10 : GW_A07 : DISCONNECTED White,Yellow : GW_A10 : GW_C06 : GW_Z01 White,Yellow : GW_A11 : GW_D04 : GW_H15 White,Yellow : GW_A11 : 1 : GW_K24 White,Yellow : GW_A11 : 2 : GW_X56</pre> Would functionally transform the previous rooms lines to the following when playing as Survivor or Monk: <pre>GW_A10 : GW_D01, DISCONNECTED, GW_Z01 GW_A11 : GW_B01, GW_H15, GW_K24, GW_F07, GW_X56</pre> == room_settings.txt == Room settings files can be suffixed by a slugcat name to make a set of room settings exclusive to a specific slugcat campaign. (ie: <code>su_c03_settings-red.txt</code>) The following entities inside settings files now save by value rather than by index: * Any entities that use slugcat filter lists save the filter list by names rather than a binary flag. Importantly, the names listed are the slugcats who are ''excluded'' from the filter (ie: slugcats who would have had a 0 in the binary string). * Entities with filters include: ** Filter ** Unlock tokens (GoldToken/BlueToken) ** Trigger events (<code>event&lt;tB&gt;</code>) * For these filter lists, when multiple slugcats need to be excluded, their names should be separated by the | character. * <code>DataPearl/UniqueDataPearl</code>: <code>UniqueDataPearl&gt;&lt;2550.05&gt;&lt;2104.999&gt;&lt;37~172~0~0~<u>14</u>~0</code> -&gt; <code>UniqueDataPearl&gt;&lt;2550.05&gt;&lt;2104.999&gt;&lt;37~172~0~0~<u>SL_moon</u>~0</code>. * The type field for <code>StopMusicEvent</code> uses <code>AllSongs/SpecificSong/AllButSpecific</code> instead of <code>0/1/2</code> respectively. == Threat Music metadata files == * Prefix an instrument in a layer with {D} to make it only play during the daytime (redundant/irrelevant if region doesn't use day-night cycles) * Prefix an instrument in a layer with {N} to make it only play during the nighttime (irrelevant if the region doesn't use day-night cycles) * Prefix an instrument in a layer with {M} to make it only play while the player is under the influence of mushrooms. * Prefix an instrument with a subregion name between <code>{}</code> to make it only play in that subregion. Multiple subregions can be specified by separating them with the pipe character (<code>|</code>). ** Example: <code>{Five Pebbles (Recursive Transform Array)|Five Pebbles (Unfortunate Development)}TH_SS - NOISE''</code> == Short Strings == Each language has its own separate short strings file located at <code>text_xxx/short_strings/strings.txt</code>. Each line of this file is a Key|Value pair. efdb42b974dbb85a35cdd782a0c585c4ed3604de 353 350 2022-12-19T04:43:01Z AndrewFM 14 /* world_xx.txt */ Inversion prefix wikitext text/x-wiki Certain file formats have marginally changed in Downpour with the most common difference being that many things are now stored by value rather than by index. Some files also support new fields / attributes / parameters for new features. Most of these changes are optional and the files will still be parsed properly via backwards compatibility if still stored as indices, but updating may improve mod compatibility for the future. == locks.txt == This is the same, but " : SWAPMAPSYMBOL" can be added to the end of a line to swap the order that the two gate symbols appear on the in-game mini-map. == egates.txt == <code>egates.txt</code> is a new file in the same folder as locks.txt. Placing a gate room name as a new line in this file makes the gate an electric gate. == properties.txt == * Slugcats listed under Broken Shelters should be listed by name rather than index. (<code>Broken Shelters: <u>2</u>: SL_S11''"</code> -&gt; <code>Broken Shelters: <u>Red</u>: SL_S11</code>) * <code>blackSalamanderChance</code> is a new parameter that can be used to change the probability of salamanders in this region spawning as their dark variant. (Default: <code>blackSalamanderChance: 0.33</code>) * <code>corruptionEffectColor</code> is a new parameter than can be used to change the effect color of corruption objects and BLL creatures in the region. (Default <code>corruptionEffectColor: 0.0,0.0,1.0</code>) * <code>corruptionEyeColor</code> is a new parameter than can be used to change the eye color of corruption objects and BLL creatures in the region. (Default <code>corruptionEffectColor: 0.0,0.0,1.0</code>) * <code>kelpColor</code> is a new parameter that can be used to change the color of kelp creatures in the region. * <code>albinos</code> is a new parameter that can make relevant creautres spawn as their albino variants in a region. (Default <code>albinos: false</code>) * <code>waterColorOverride</code> is a new parameter that can change the color that water appears on the in-game minimap for the region. (Default <code>waterColorOverride: 0.05,0.05,0.8</code>) * <code>earlyCycleChance</code> is a new parameter that can set the probability of a pre-cycle event occurring at the start of a cycle in the region. (MSC only) * <code>earlyCycleFloodChance</code> is a new parameter that can set the probability of partial region flooding occuring during a pre-cycle event in this region. (MSC only) * <code>scavsDelayInitialMin</code> is a new parameter that sets the minimum time in ticks before a kill squad will be sent after a disliked player after entering this region. (default 4200) * <code>scavsDelayInitialMax</code> is a new parameter that sets the maximum time in ticks before a kill squad will be sent after a disliked player after entering this region. (default 8200) * <code>scavsDelayRepeatMin</code> is a new parameter that sets the minimum time in ticks before a support squad will be sent to a liked player after entering this region. (default 1100) * <code>scavsDelayRepeatMax</code> is a new parameter that sets the maximum time in ticks before a support squad will be sent to a liked player after entering this region. (default 1700) * Room_Attr lists attractiveness with <code>Neutral,Forbidden,Avoid,Like,Stay</code> instead of <code>0,1,2,3,4</code> respectively -- but it is optional to update this. Properties files can be suffixed by a slugcat name to make a region properties file exclusive to a specific slugcat campaign. (ie: properties-red.txt would apply the properties only while playing as Hunter). == map_xx.txt/map_xx.png == Map files can be suffixed by a slugcat name to make a map render exclusive to a specific slugcat campaign. (ie: <code>map_xx-red.png</code>) == displayname.txt == '''This file is required'''. This file contains a single line that contains the name of the region. This exists in the same folder as the properties / world_xx files. Display name files can also be provided that are suffixed by a slugcat name to change the name of the region for specific slugcat campaigns. (ie: <code>displayname-red.txt</code>) == world_xx.txt == Slugcat-specific spawn lines should be listed by name rather than index. (<code>(<u>0,1</u>)CC_A07 : 3-Mimic-{18}</code> -&gt; <code>(<u>White,Yellow</u>)CC_A07 : 3-Mimic-{18}</code>). Additionally, an "X-" prefix can be added to slugcat-specific spawn filters to invert the filter. For example <code>(<u>X-White,Yellow</u>)CC_A07 : 3-Mimic-{18}</code> would make the spawner appear on any slugcats ''except for'' Survivor and Monk. A new "CONDITIONAL LINKS"/"END CONDITIONAL LINKS" section can be added before the "ROOMS"/"END ROOMS" section in the file to specify room connection changes that apply to specific slugcats. There are three types of conditional link lines: * <code>SLUGCAT : HIDEROOM : ROOM</code> - This excludes the given room from the region when playing as the specified slugcat(s). ** (Example) <code>White,Yellow : HIDEROOM : SU_A99</code> * <code>SLUGCAT : EXCLUSIVEROOM : ROOM</code> - This includes the given room in the region only when playing as the selected slugcat(s). ** (Example) <code>White,Yellow : EXCLUSIVEROOM : SU_A99</code> * <code>SLUGCAT : TARGET_ROOM : TARGET_CONNECTION_ROOM : NEW_CONNECTION_ROOM</code> - This changes the given room connection in the target room to now connect to a different specified room while playing as the specified slugcat(s). For the last conditional link type, the "TARGET_CONNECTION_ROOM" is specified by the room name for named room connections, or with a number to target a DISCONNECTED connection (1 for the first DISCONNECTED pipe in the room, 2 for the second DISCONNECTED, etc). To give an example for this last conditional link line type, imagine the following line existed in the ROOMS/END ROOMS section of the file: <pre>GW_A10 : GW_D01, GW_A07, GW_C06 GW_A11 : GW_B01, GW_D04, DISCONNECTED, GW_F07, DISCONNECTED</pre> Then the following conditional links lines: <pre>White,Yellow : GW_A10 : GW_A07 : DISCONNECTED White,Yellow : GW_A10 : GW_C06 : GW_Z01 White,Yellow : GW_A11 : GW_D04 : GW_H15 White,Yellow : GW_A11 : 1 : GW_K24 White,Yellow : GW_A11 : 2 : GW_X56</pre> Would functionally transform the previous rooms lines to the following when playing as Survivor or Monk: <pre>GW_A10 : GW_D01, DISCONNECTED, GW_Z01 GW_A11 : GW_B01, GW_H15, GW_K24, GW_F07, GW_X56</pre> == room_settings.txt == Room settings files can be suffixed by a slugcat name to make a set of room settings exclusive to a specific slugcat campaign. (ie: <code>su_c03_settings-red.txt</code>) The following entities inside settings files now save by value rather than by index: * Any entities that use slugcat filter lists save the filter list by names rather than a binary flag. Importantly, the names listed are the slugcats who are ''excluded'' from the filter (ie: slugcats who would have had a 0 in the binary string). * Entities with filters include: ** Filter ** Unlock tokens (GoldToken/BlueToken) ** Trigger events (<code>event&lt;tB&gt;</code>) * For these filter lists, when multiple slugcats need to be excluded, their names should be separated by the | character. * <code>DataPearl/UniqueDataPearl</code>: <code>UniqueDataPearl&gt;&lt;2550.05&gt;&lt;2104.999&gt;&lt;37~172~0~0~<u>14</u>~0</code> -&gt; <code>UniqueDataPearl&gt;&lt;2550.05&gt;&lt;2104.999&gt;&lt;37~172~0~0~<u>SL_moon</u>~0</code>. * The type field for <code>StopMusicEvent</code> uses <code>AllSongs/SpecificSong/AllButSpecific</code> instead of <code>0/1/2</code> respectively. == Threat Music metadata files == * Prefix an instrument in a layer with {D} to make it only play during the daytime (redundant/irrelevant if region doesn't use day-night cycles) * Prefix an instrument in a layer with {N} to make it only play during the nighttime (irrelevant if the region doesn't use day-night cycles) * Prefix an instrument in a layer with {M} to make it only play while the player is under the influence of mushrooms. * Prefix an instrument with a subregion name between <code>{}</code> to make it only play in that subregion. Multiple subregions can be specified by separating them with the pipe character (<code>|</code>). ** Example: <code>{Five Pebbles (Recursive Transform Array)|Five Pebbles (Unfortunate Development)}TH_SS - NOISE''</code> == Short Strings == Each language has its own separate short strings file located at <code>text_xxx/short_strings/strings.txt</code>. Each line of this file is a Key|Value pair. 1ac66e836f34166358dc555d1288da583340f01b Downpour Reference/Modification Files 0 146 351 284 2022-12-18T08:23:01Z AndrewFM 14 Adding additional available modification file operations wikitext text/x-wiki Modification files are a method to specify rules to partially modify the contents an existing (non-binary) file, rather than replacing that file's contents completely. For compatibility between mods, these are preferable, as multiple mods can apply modifications to the same file without overwriting each other's changes. Think of this like the file system equivalent of a hook mod versus a patch mod. == Modification Directory Structure == Targeting a file for modification works similarly to targeting a file for overwriting. The difference is that these modification files are placed within an additional subdirectory within your mod folder called <code>modify</code>. For example, for the file: : <code>Assets/StreamingAssets/world/gates/locks.txt</code> Placing a file at: : <code>your-mod-folder/world/gates/locks.txt</code> Would cause the entire contents of locks.txt to be overwritten by the entire contents of the locks.txt file in your mod's folder. However, placing a modification file at: : <code>your-mod-folder/modify/world/gates/locks.txt</code> Would apply the modification syntax within that locks.txt file to partially modify the contents of the original locks.txt file. == Modification File Syntax == Each line of a modification file includes an operation followed by the text that the operation uses for applying its effect. {|class="wikitable" |+Available operations ! Keyword !! Action |- | '''[ADD]''' || Appends the specified text to the end of the file. |- | '''[ADD_XX]''' || Inserts the specified text after the XXth line in the file. |- | '''[FIND]''' || Set a specific string as a target for a subsequent replace operation. |- | '''[FINDREGEX]''' || Set a specific regex pattern as the target for a subsequent replace operation. |- | '''[FINDLINE]''' || Target an entire line in the file which contains the given substring, for a subsequent replace operation. |- | '''[FINDLINEREGEX]''' || Target an entire line in the file which contains the given regular expression match, for a subsequent replace operation. |- | '''[FINDLINESTART]''' || Target an entire line in the file which starts with the given substring, for a subsequent replace operation. |- | '''[FINDLINEEND]''' || Target an entire line in the file which ends with the given substring, for a subsequent replace operation. |- | '''[TARGETLINE]''' || Target the entire line in the file at the given line number, for a subsequent replace operation. |- | '''[REPLACE]''' || Replace all instances of the target from the preceding find operation with the given text. |- | '''[REPLACE_XX]''' || Replace the XXth instance of the target from the preceding find operation with the given text. If targeting a substring, this affects the XXth instance of that substring in the file. If targeting a line, this affects the XXth instance of a line that contains that substring (rather than affecting the line which contains the XXth instance of the substring). |- | '''[ADDBEFORE]''' || Add the given string before all instances of the targeted text from the preceding find operation. |- | '''[ADDBEFORE_XX]''' || Add the given string before the XXth occurrence of the targeted text from the preceding find operation. (Same targeting/affecting behavior as REPLACE_XX) |- | '''[ADDAFTER]''' || Add the given string after all instances of the targeted text from the preceding find operation. |- | '''[ADDAFTER_XX]''' || Add the given string after the XXth occurrence of the targeted text from the preceding find operation. (Same targeting/affecting behavior as REPLACE_XX) |} If a new-line character needs to be matched or added, use the \n escape character to represent the new line. Also note that you can effectively do a delete operation as well by using [FIND]/[REPLACE] operations to replace the target with an empty string. Below is an example modification file: <pre>[ADD]Hello World [ADD_5]Slugcat\nRain World [FIND]Spider [REPLACE]Centipede [FINDREGEX](Green,Blue,Pink) [REPLACE_1]Red</pre> The above example modification file performs the following actions: # Appends a new line to the end of the file containing the text "Hello World". # Inserts two new lines after line 5 in the file, the first containing the text "Slugcat" and the second containing the text "Rain World". # Finds all instances of the text "Spider" in the file and replaces all those instances with the text "Centipede". # Finds any instances of the text "Green", "Blue", or "Pink" in the file, and replaces only the first instance it finds with the text "Red". == Merge Operation == Modification files have one more operation that is used by placing any number of lines of text between a <code>[MERGE]</code> and an <code>[ENDMERGE]</code> tag. The contents within will be "merged" with the contents of the original file in a way that is context dependent on the file you are applying the merge to. This section describes how this merging works for different vanilla source files: {|class="wikitable" ! style="width: 18%"| Files !! style="width: 82%"| Merge behaviour |- | '''mpmusic.txt, regions.txt, egates.txt''' || Applying merging to one of the files above will take any lines within the merge context and append them to the file, only if that line does not already exist in the file. |- | '''default aligments.txt, sounds.txt, locks.txt, properties.txt, map_XX.txt''' || Applies merging similarly to above, but takes key-value context into account. If a key doesn't exist in the file, the key-value pair will be appended to the file. If a key does exist in the file, then its value will be replaced by the new value in the merge context. |- | '''Room Settings files''' || Applies merging similarly to above, but certain keys have special handling. Effects, PlacedObjects, AmbientSounds, and Triggers will be merged additively, so the resulting room settings file will have all of the objects from the original room settings file, plus all of the new objects specified within the merge context. |- | '''world_XX files''' || Applies merging of world file contents in a CRS-style fashion. |- | '''short_strings file''' || Applying merging to a short_strings file will unencrypt the short_strings file, append any key-value pairs within the merge context if the key doesn't already exist (otherwise update the value to the new value), and then finally encrypt the short_strings file again. |- | '''anything else''' || Any other files not described above, will have their entire contents simply replaced with the contents of the merge context. |} 2667908ce71632e1a8f4b8993371e537548c57d1 352 351 2022-12-18T08:29:42Z AndrewFM 14 wikitext text/x-wiki Modification files are a method to specify rules to partially modify the contents an existing (non-binary) file, rather than replacing that file's contents completely. For compatibility between mods, these are preferable, as multiple mods can apply modifications to the same file without overwriting each other's changes. Think of this like the file system equivalent of a hook mod versus a patch mod. == Modification Directory Structure == Targeting a file for modification works similarly to targeting a file for overwriting. The difference is that these modification files are placed within an additional subdirectory within your mod folder called <code>modify</code>. For example, for the file: : <code>Assets/StreamingAssets/world/gates/locks.txt</code> Placing a file at: : <code>your-mod-folder/world/gates/locks.txt</code> Would cause the entire contents of locks.txt to be overwritten by the entire contents of the locks.txt file in your mod's folder. However, placing a modification file at: : <code>your-mod-folder/modify/world/gates/locks.txt</code> Would apply the modification syntax within that locks.txt file to partially modify the contents of the original locks.txt file. == Modification File Syntax == Each line of a modification file includes an operation followed by the text that the operation uses for applying its effect. {|class="wikitable" |+Available operations ! Keyword !! Action |- | '''[ADD]''' || Appends the specified text to the end of the file. |- | '''[ADD_XX]''' || Inserts the specified text after the XXth line in the file. |- | '''[FIND]''' || Set a specific string as a target for a subsequent replace operation. |- | '''[FINDREGEX]''' || Set a specific regex pattern as the target for a subsequent replace operation. |- | '''[FINDLINE]''' || Target an entire line in the file which contains the given substring, for a subsequent replace operation. |- | '''[FINDLINEREGEX]''' || Target an entire line in the file which contains the given regular expression match, for a subsequent replace operation. |- | '''[FINDLINESTART]''' || Target an entire line in the file which starts with the given substring, for a subsequent replace operation. |- | '''[FINDLINEEND]''' || Target an entire line in the file which ends with the given substring, for a subsequent replace operation. |- | '''[TARGETLINE]''' || Target the entire line in the file at the given line number, for a subsequent replace operation. |- | '''[REPLACE]''' || Replace all instances of the target from the preceding find operation with the given text. |- | '''[REPLACE_XX]''' || Replace the XXth instance of the target from the preceding find operation with the given text. Note: *If used with a FIND operation that targets a substring/pattern, this affects the XXth instance of that pattern in the file. *If used with a FIND operation that targets a line, this affects the XXth instance of a line that contains the pattern (not necessarily the line which contains the XXth instance of the pattern). *This and the other "_XX" operations cannot be used together with [TARGETLINE]. |- | '''[ADDBEFORE]''' || Add the given string before all instances of the targeted text from the preceding find operation. |- | '''[ADDBEFORE_XX]''' || Add the given string before the XXth occurrence of the targeted text from the preceding find operation. (Same targeting/affecting behavior as REPLACE_XX) |- | '''[ADDAFTER]''' || Add the given string after all instances of the targeted text from the preceding find operation. |- | '''[ADDAFTER_XX]''' || Add the given string after the XXth occurrence of the targeted text from the preceding find operation. (Same targeting/affecting behavior as REPLACE_XX) |} If a new-line character needs to be matched or added, use the \n escape character to represent the new line. Also note that you can effectively do a delete operation as well by using [FIND]/[REPLACE] operations to replace the target with an empty string. Below is an example modification file: <pre>[ADD]Hello World [ADD_5]Slugcat\nRain World [FIND]Spider [REPLACE]Centipede [FINDREGEX](Green,Blue,Pink) [REPLACE_1]Red</pre> The above example modification file performs the following actions: # Appends a new line to the end of the file containing the text "Hello World". # Inserts two new lines after line 5 in the file, the first containing the text "Slugcat" and the second containing the text "Rain World". # Finds all instances of the text "Spider" in the file and replaces all those instances with the text "Centipede". # Finds any instances of the text "Green", "Blue", or "Pink" in the file, and replaces only the first instance it finds with the text "Red". == Merge Operation == Modification files have one more operation that is used by placing any number of lines of text between a <code>[MERGE]</code> and an <code>[ENDMERGE]</code> tag. The contents within will be "merged" with the contents of the original file in a way that is context dependent on the file you are applying the merge to. This section describes how this merging works for different vanilla source files: {|class="wikitable" ! style="width: 18%"| Files !! style="width: 82%"| Merge behaviour |- | '''mpmusic.txt, regions.txt, egates.txt''' || Applying merging to one of the files above will take any lines within the merge context and append them to the file, only if that line does not already exist in the file. |- | '''default aligments.txt, sounds.txt, locks.txt, properties.txt, map_XX.txt''' || Applies merging similarly to above, but takes key-value context into account. If a key doesn't exist in the file, the key-value pair will be appended to the file. If a key does exist in the file, then its value will be replaced by the new value in the merge context. |- | '''Room Settings files''' || Applies merging similarly to above, but certain keys have special handling. Effects, PlacedObjects, AmbientSounds, and Triggers will be merged additively, so the resulting room settings file will have all of the objects from the original room settings file, plus all of the new objects specified within the merge context. |- | '''world_XX files''' || Applies merging of world file contents in a CRS-style fashion. |- | '''short_strings file''' || Applying merging to a short_strings file will unencrypt the short_strings file, append any key-value pairs within the merge context if the key doesn't already exist (otherwise update the value to the new value), and then finally encrypt the short_strings file again. |- | '''anything else''' || Any other files not described above, will have their entire contents simply replaced with the contents of the merge context. |} d9e5ddd05948f93ab69494acf0148596977332d5 BepInPlugins 0 95 356 156 2023-01-15T05:50:46Z Dual 37 Include SecurityPermission declaration in example plugin wikitext text/x-wiki BepInPlugins are a kind of game mod native to [[BepInEx]]. They are not compatible with Partiality. They should be placed in <code>Rain World/BepInEx/plugins</code>. == Creating a BepInPlugin == === Prerequisites === * A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary) * Rain World with RW BepInEx set up - see [[BepInEx|here]]. * Some kind of .NET programming environment, probably Visual Studio if you're on Windows, or Visual Studio Code for Linux/Mac. The guide below will assume you're already comfortable with the first prerequisite and your editor and environment of choice. ** The .NET Development pack for Visual Studio (or similar for other environments - you need to be able to use .NET Framework 3.5) === Step 1 - The project === Create a new C# .NET Framework 3.5 Class Library project in your IDE. You will then need to [https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019 add some references]. It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/plugins/PartialityWrapper/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/core/BepInEx.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/Assembly-CSharp.dll</code> - note: you will need to modify this before accessing private members; see the section "Replacement of Publicity Stunt" on [[BepInEx]] page. === Step 2 - The BepInPlugin class === In a your new C# file, make a public class that has the <code>BepInEx.BepInPlugin</code> attribute and inherits from <code>BepInEx.BaseUnityPlugin</code> . The <code>BaseUnityPlugin</code> class inherits from <code>MonoBehaviour</code>, so you can use standard Unity script methods such as <code>OnEnable</code> and <code>OnDisable</code> in this class. The GUID should be unique to this plugin: something like "scholar" could be popular, which may result in BepInEx not loading your mod. Usually, people opt for the <code>username.mode_name</code> format. Include an assembly-level <code>SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)</code> declaration alongside your plugin class. This prevents errors later down the line. <syntaxhighlight lang="csharp"> using BepInEx; using System.Security.Permissions; [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] namespace SomeMod {     [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] // (GUID, mod name, mod version)     public class MyModName : BaseUnityPlugin     {     } } </syntaxhighlight> === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example:<syntaxhighlight lang="csharp"> [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] public class MyMod : BaseUnityPlugin {     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         /* This method will be subscribed to Player.Update. */         orig(self, eu);         /* Calling orig is what allows the original method and          * other hooks to the same method do their thing.          * Not calling this is almost always undesirable, and          * can cause big issues.          *   You can execute code before or after the call of          * orig as necessary.          */     } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote>Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and copy the mod's DLL file from wherever your build output is to <code>Rain World/BepInEx/plugins/</code> and run Rain World. == Enums == Due to their abundance in Rain World's code and their general usefulness in state machines, it's very possible that at some point you'll want to add your own value to an enum. To do that, you can use [[EnumExtender]]. == Advanced Techniques == === IL Hooking === IL hooking can be used to modify the Intermediate Language (IL) instructions of the game at runtime. This allows advanced editing of individual instructions within the game code. Risk of Thunder's guide to IL hooking can be found [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ here]. === RuntimeDetour === RuntimeDetour can be used to hook methods not covered by HOOKS-Assembly-CSharp.dll, as well as property getters and setters. A brief guide can be found on the [[MonoMod RuntimeDetour]] page. MonoMod's RuntimeDetour guide can be found [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md here]. === Harmony Patching === Harmony patching is a form of runtime patching. The HarmonyX wiki can be found [https://github.com/BepInEx/HarmonyX/wiki here]. [[Category:Code Mods]] 00750b81b6b7970f026a63e9b793d83680ad3308 360 356 2023-01-23T12:14:45Z SabreML 46 Upped the suggested .NET version from 3.5 to 4.8, and updated & alphabetised the reference list. wikitext text/x-wiki BepInPlugins are a kind of game mod native to [[BepInEx]]. They are not compatible with Partiality. They should be placed in <code>Rain World/BepInEx/plugins</code>. == Creating a BepInPlugin == === Prerequisites === * A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary) * Rain World with RW BepInEx set up - see [[BepInEx|here]]. * Some kind of .NET programming environment, probably Visual Studio if you're on Windows, or Visual Studio Code for Linux/Mac. The guide below will assume you're already comfortable with the first prerequisite and your editor and environment of choice. ** The .NET Development pack for Visual Studio (or similar for other environments - you need to be able to use .NET Framework 4.8) === Step 1 - The project === Create a new C# .NET Framework 4.8 Class Library project in your IDE. You will then need to [https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019 add some references]. It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/core/BepInEx.dll</code> * <code>BepInEx/plugins/HOOKS-Assembly-CSharp.dll</code> * <code>RainWorld_Data/Managed/Assembly-CSharp.dll</code> - note: you will need to modify this before accessing private members; see the section "Replacement of Publicity Stunt" on [[BepInEx]] page. * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.CoreModule.dll</code> === Step 2 - The BepInPlugin class === In a your new C# file, make a public class that has the <code>BepInEx.BepInPlugin</code> attribute and inherits from <code>BepInEx.BaseUnityPlugin</code> . The <code>BaseUnityPlugin</code> class inherits from <code>MonoBehaviour</code>, so you can use standard Unity script methods such as <code>OnEnable</code> and <code>OnDisable</code> in this class. The GUID should be unique to this plugin: something like "scholar" could be popular, which may result in BepInEx not loading your mod. Usually, people opt for the <code>username.mode_name</code> format. Include an assembly-level <code>SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)</code> declaration alongside your plugin class. This prevents errors later down the line. <syntaxhighlight lang="csharp"> using BepInEx; using System.Security.Permissions; [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] namespace SomeMod {     [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] // (GUID, mod name, mod version)     public class MyModName : BaseUnityPlugin     {     } } </syntaxhighlight> === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example:<syntaxhighlight lang="csharp"> [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] public class MyMod : BaseUnityPlugin {     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         /* This method will be subscribed to Player.Update. */         orig(self, eu);         /* Calling orig is what allows the original method and          * other hooks to the same method do their thing.          * Not calling this is almost always undesirable, and          * can cause big issues.          *   You can execute code before or after the call of          * orig as necessary.          */     } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote>Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and copy the mod's DLL file from wherever your build output is to <code>Rain World/BepInEx/plugins/</code> and run Rain World. == Enums == Due to their abundance in Rain World's code and their general usefulness in state machines, it's very possible that at some point you'll want to add your own value to an enum. To do that, you can use [[EnumExtender]]. == Advanced Techniques == === IL Hooking === IL hooking can be used to modify the Intermediate Language (IL) instructions of the game at runtime. This allows advanced editing of individual instructions within the game code. Risk of Thunder's guide to IL hooking can be found [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ here]. === RuntimeDetour === RuntimeDetour can be used to hook methods not covered by HOOKS-Assembly-CSharp.dll, as well as property getters and setters. A brief guide can be found on the [[MonoMod RuntimeDetour]] page. MonoMod's RuntimeDetour guide can be found [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md here]. === Harmony Patching === Harmony patching is a form of runtime patching. The HarmonyX wiki can be found [https://github.com/BepInEx/HarmonyX/wiki here]. [[Category:Code Mods]] 8502deda769b833627595eb19c529a225d86b9cf ConfigMachine 0 115 357 253 2023-01-15T15:18:25Z PJB 38 Fix incorrect code sample with return statement in expression body method. wikitext text/x-wiki '''Configmachine''' is a dependency mod that allows other mods to easily create in-game config GUI. It's currently shipped with [[BepInEx]] installation. == Features == === OptionInterface === This is the most common method of adding config screen to your mod. ==== Registering ==== '''OptionalUI.OptionInterface''' is the base class for option interfaces. <syntaxhighlight lang="csharp"> public class MyOI : OptionInterface { public MyOI() : base (plugin: MyPlugin.instance) // Your BaseUnityPlugin instance. Examples assume you have a static singleton instance of your mod. { } } </syntaxhighlight> Now add <code>LoadOI</code> static method in your <code>BaseUnityPlugin</code> class that returns your OptionInterface. <syntaxhighlight lang="c#"> public static OptionInterface LoadOI() => new MyOI(); //set return type to "object" if you want your mod to be loaded even if CM is not. In that case, you will need to handle CM's absence on your own. </syntaxhighlight> ==== Designing GUI ==== For designing your GUI, using [https://inkscape.org/ Inkscape] is strongly suggested. With Inkscape, create a file with 600 x 600 pixel resolution, then enable [View] - [Canvas Orientation] - [Flip Vertically]. (Alternatively, you can use any CAD program which has up and right as positive axis by default) <!--The image below is a diagram of <code>Colorfoot</code>’s first <code>OpTab</code>.--> [[File:Colorfoot-GUI.png|thumb|right|alt=Colorfoot's GUI as an example|Colorfoot's GUI as an example]] All UIelements have bottom-left <code>pos</code>ition and rectangular <code>size</code>. (Some have <code>fixedSize</code> which you can see from the summary of their constructors). Think every element like rectangles, and arrange them as you need. (Circular UIelements have <code>rad</code> instead; You can consider them as a square with 2 * rad for its dimensions) [[File:Colorfoot-GUI0.png|thumb|none|alt=Example GUI Positioning|Example GUI Positioning]] For <code>pos</code> parameters, use the relative coordinate from bottom-left from the canvas to your item. For <code>size</code> parameters, use their size in pixel. If you’re using Inkscape with [Flip Vertically] setting on, you can get those from their properties without any calculation. [[File:Colorfoot-Inkscape.png|thumb|none|alt=Example GUI Inkscape|Example GUI in Inkscape]] Here are some tips for designing GUI: * If you have many things to display, organise them with categories and use <code>OpRect</code> to surround them. * You don’t have to put everything in a single <code>OpTab</code>. If the canvas gets crowded, disperse your items for easier readability. * Try to avoid using smaller <code>OpScrollBox</code>s to store many things in one place even if that’s an option: The users cannot see everything in a single screen which reduces usability greatly. ==== Initialization ==== <code>OptionInterface.Initialize</code> is called in IntroRoll(for loading configuration) and ConfigMenu (for displaying to users). You can check whether Initialize is called in ConfigMenu or not with <code>OptionInterface.isOptionMenu</code>. It usually goes like this following example: <syntaxhighlight lang="csharp"> public override void Initialize() { base.Initialize(); // This should be called before everything else Tabs = new OpTab[2]; // you can have up to 20 tabs Tabs[0] = new OpTab("Main"); // Each OpTab is 600 x 600 pixel sized canvas Tabs[1] = new OpTab("Second") { color = Color.cyan }; // You can change its button and canvas colour too // After Initializing Tabs, create UIelements and add them to tabs } </syntaxhighlight> Now initialize <code>UIelement</code>s and add them to <code>OpTab</code> (or <code>OpScrollBox</code>). The Z-order (the order in which they’re drawn) of <code>UIelement</code>s is the order of constructors, ''not'' the order they’re added to <code>OpTab</code>. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpLabel(100f, 500f, "My Text") { description = "This is My Text" }); // Any UIelement can have description, which will be shown // at the bottom of the screen when the mouse cursor is over it </syntaxhighlight> <code>UIconfig</code>s are a subcategory of <code>UIelement</code> which have <code>key</code> and <code>value</code> for storing user input values, both of them get saved automatically by Config Machine. Their constructor accepts <code>key</code> and <code>defaultValue</code> on top of everything else. <code>key</code> must be unique for all elements in your OI unless they are cosmetic. Setting the key to empty or anything that starts with <code>_</code> (underbar) will turn it <code>cosmetic</code>, and the value won’t be saved. Cosmetic UIconfig is useful when you want to have provided <code>UIconfig</code> for UI purpose but not for an actual configurable. (Similarly, ModID that starts with <code>_</code> will be completely ignored by Config Machine) <syntaxhighlight lang="csharp"> OpCheckBox chkExample = new OpCheckBox(260f, 360f, "Example", true); Tabs[0].AddItems(chkExample, new OpLabel(260f, 390f, "Enable Example") { bumpBehav = chkExample.bumpBehav }); // BumpBehaviour is Config Machine's custom class that allows smoothly animated reaction with the input // Setting OpLabel's bumpBehav to other UIconfig/UItrigger's bumpBehav allows it to highlight with that element </syntaxhighlight> <code>UItrigger</code>s are the other subcategory of <code>UIelement</code>s which have <code>signal</code>s. When the user activates an <code>UItrigger</code> in some way, it will call the <code>Signal</code> function in OptionInterface which will be explained later. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpSimpleButton(new Vector2(400f, 200f), new Vector2(100f, 24f), "press", "Press Me")); </syntaxhighlight> ==== Update ==== <code>Update</code> function is called every frame when the game is in ConfigMenu, and this OptionInterface is currently active (The user has currently selected this mod from the list on left). This is useful to make reactive GUI, especially since each <code>UIconfig</code> instance can have only one value saved. The following example code uses cosmetic <code>OpRadioButtonGroup</code> to have four <code>OpColorPicker</code>s in a single spot. <syntaxhighlight lang="csharp"> private OpRadioButtonGroup rbgSelect; private int select; private OpColorPicker[] cpkPlayers; public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; select = 0; rbgSelect = new OpRadioButtonGroup("_", select); Tabs[0].AddItems(rbgSelect); rbgSelect.SetButtons(new OpRadioButton[] { new OpRadioButton(50f, 100f){ description = "The Survivor"}, new OpRadioButton(100f, 100f){ description = "The Monk"}, new OpRadioButton(150f, 100f){ description = "The Hunter"}, new OpRadioButton(200f, 100f){ description = "The Nightcat"} } ); OpColorPicker[] cpkPlayers = new OpColorPicker[4]; for (int i = 0; i < 4; i++) { Tabs[0].AddItems(new OpLabel(50f * i, 70f, rbgSelect.buttons[i].description) { bumpBehav = rbgSelect.buttons[i].bumpBehav }); cpkPlayers[i] = new OpColorPicker(new Vector2(100f, 300f), $"Color{i}", "FFFFFF"); cpkPlayers[i].Hide(); } cpkPlayers[select].Show(); Tabs[0].AddItems(cpkPlayers); } public override void Update(float dt) { base.Update(dt); // dt is deltaTime if (select != rbgSelect.valueInt) { for (int i = 0; i < cpkPlayers.Length; i++) { cpkPlayers[i].Hide(); } select = rbgSelect.valueInt; cpkPlayers[select].Show(); } } </syntaxhighlight> ==== ConfigOnChange ==== <code>ConfigOnChange</code> is called whenever <code>config</code> Dictionary is updated, mainly when Config Machine loads OptionInterfaces in IntroRoll, and when the user saves changes of configuration in ConfigMenu. Override this method to grab your configurable values. <code>config</code> Dictionary is where <code>UIconfig</code>’s value is stored. The following is an example of how to convert a string value to the corresponding type. <syntaxhighlight lang="csharp">public override void ConfigOnChange() { base.ConfigOnChange(); MyMod.config.myInt = int.Parse(config["keyInt"]); MyMod.config.myFloat = float.Parse(config["keyFloat"]); MyMod.config.myKey = OpKeyBinder.StringToKeyCode(config["keyKey"]); MyMod.config.myColor = OpColorPicker.HexToColor(config["keyColor"]); } </syntaxhighlight> ==== Signal ==== <code>Signal</code> is called when the user has interacted with <code>UItrigger</code>. Override this to have your OI to react. <syntaxhighlight lang="csharp"> public override void Signal(UItrigger trigger, string signal) { switch (signal) { case "reset": ConfigMenu.ResetCurrentConfig(); // This is the same as pressing Reset Config Button. break; } } </syntaxhighlight> === Generated OIs === <code>GeneratedOI</code> is a child class of <code>OptionInterface</code> that helps generating fixed-format GUI with less effort. <span id="displaying-basic-profile"></span> ==== Displaying Basic Profile ==== Simply inheriting <code>GeneratedOI</code> instead of <code>OptionInterface</code> works. This does make your mod dependent to Config Machine, and Config Machine generates GUI to display the basic information of your mod without this dependency. So this is only useful when you’re using OptionInterface for other features, like its Translation API. <syntaxhighlight lang="c#"> public class MyOI : GeneratedOI { private const string desc = "Changes this thing and that thing"; public MyOI() : base(plugin: MyPlugin.instance, desc) { transFile = "MyPlugin.Translation.txt"; } } </syntaxhighlight> The code above would generate a GUI like the following image: [[File:GeneratedOI-sample.png|thumb|none|alt=GeneratedOI Sample|GeneratedOI Sample]] You can also use its static method <code>AddBasicProfile</code> for basic profiles on top of the canvas. This also has an overload that accepts <code>OpScrollBox</code> instead of <code>OpTab</code>, if you have <code>OpScrollBox</code> replacing <code>OpTab</code>. <syntaxhighlight lang="c#"> public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; GeneratedOI.AddBasicProfile(Tabs[0], rwMod); Tabs[0].AddItems(new OpCheckBox(100f, 350f, "EnableStuff", false) { description = "Enables this stuff" }); } </syntaxhighlight> ==== BepInEx.Configuration ==== If you don't provide an OptionInterface, BepInEx can generate a simple config screen from your [[BepInPlugins|plugin]]'s config bindings (see <code>BepInEx.Configuration</code>). If this happens, CM will not create a separate file to store your config values. This method has upsides and downsides. * You don’t need to reference Config Machine in your project, and this doesn’t create a dependency for Config Machine. * The users can configure the plugin by opening the cfg file in Notepad outside the game. * However, you do not have control on detailed GUI design. First, we need <code>ConfigEntry</code> which you can bind to the <code>Config</code> property of <code>BaseUnityPlugin</code>. Consult [https://docs.bepinex.dev/articles/dev_guide/plugin_tutorial/4_configuration.html BepInEx Documentation] for farther detail. <syntaxhighlight lang="c#"> public static ConfigEntry<string> cfgText; public static ConfigEntry<bool> cfgCheck; void Awake() { cfgText = Config.Bind( "General", // section: defines which OpTab this will go "My Setting", // key: the name of setting "Hello, world!" // defaultValue "This is a description. It does things." // The description will be shown the right side of UIconfig // When you hover your mouse on UIconfig, // the first sentence will be displayed at the bottom of the screen ); cfgCheck = Config.Bind("General", "My Other Setting", true, "Another description is this."); } </syntaxhighlight> To access those settings, use <code>Value</code>. <syntaxhighlight lang="c#"> if (cfgCheck.Value) { Logger.LogMessage(cfgText.Value); } </syntaxhighlight> === Translation Support === While you can support translation for your mod on your own, Config Machine also offers translation solution. ==== Preparation ==== <code>OptionInterface</code> has a method called <code>Translate</code>, and when it's initially called, it will load specified (<code>transFile</code>) txt file from your assembly and make Dictionary depending on Rain World's language setting. In <code>BaseUnityPlugin.LoadOI</code> method, store the <code>OptionInterface</code> instance in somewhere before returning it. <syntaxhighlight lang="c#"> public static MyOI oi; public static MyOI LoadOI() { oi = new MyOI(); return oi; } </syntaxhighlight> Then make a static method that calls the translation method. <syntaxhighlight lang="c#">public static string Translate(string orig) { if (oi != null) { return oi.Translate(orig); } return orig; } </syntaxhighlight> Now when you need to translate something, you can pass your string through this method. ==== Writing Translation txt ==== Create a txt file that contains translation, too. Add txt file to your project, ''make sure'' that its encoding is <code>UTF-8</code>, then set it to be [Embedded Resources] for its compile setting. Then, in the constructor of your OptionInterface, set <code>transFile</code> to that resource name. If you have not put it in any folder, it's usually <code>&lt;ProjectName&gt;.&lt;TxtFileName&gt;.txt</code>, but you might get it wrong. If it's wrong when <code>OptionInterface.Translate</code> is initially called, Config Machine will log all the resources in your assembly in exceptionLog.txt so you can copy from it. <syntaxhighlight lang="c#"> public MyOI() : base(plugin: MyPlugin.instance) { this.transFile = "MyPlugin.Translation.txt"; // if you do not know the resource name, just call Translate. // ConfigMachine will log all the resources in your assembly in exceptionLog.txt. } </syntaxhighlight> The format of the translation txt file for Config Machine is quite primitive. First, you add a keyword, then <code>|</code> for language separator, then language ID (<code>eng, ita, ger, spa, por, kor, jap, rus)</code>), <code>$</code> for another separator, then translation. If there is no translation, the translator will return the keyword, unless there is a translation for <code>eng</code>. (In that case, English "translation" will be used as default translation) The following is formatting example for txt file. <!-- corrupted korean samples have been replaced with russian, sorry folks ~~thalber --> <pre> // If the first two characters are '//', this line will be ignored. Nightcat Horn Colour|rus$Цвет рога // If you have variables, avoid using partial sentences. Not every language has the same subject-verb-object order. Press &lt;ThrowKey&gt; to stab.|rus$Нажмите &lt;ThrowKey&gt; для атаки. // When translating the shorter-phrase, the translation might be sensitive with context, but English one does not. Duplicate key causes error(You can check exceptionLog.txt for duplicates), so you can set 'eng' translation for these cases. Property_as of possession|eng$Property|rus$Собственность Property_as of quality|eng$Property|rus$Свойство // For line-breaks, use \n. (In code, it'd be \\n) Each line represents a phrase, so you can't use actual line-break in a single chunk. LINE\nBREAK|rus$ПЕРЕНОС\nСТРОКИ</pre> ==== Running Translation ==== And here are some examples in code. Yes, running every text through the <code>Translate</code> method is tedious, but this is usually how it's done in Rain World or many other games. Make sure to check your mod in another language to confirm you haven’t missed any item. <syntaxhighlight lang="c#"> labelCpkrRadio.text = MyPlugin.Translate("Nightcat Horn Colour"); instance.room.game.cameras[0].hud.textPrompt.AddMessage(MyPlugin.Translate("Press <ThrowKey> to stab.").Replace("<ThrowKey>", k.ToString())); // k is variable in this example. labelLineBreak.text = MyPlugin.Translate("LINE\\nBREAK"); </syntaxhighlight> <!-- These aren't the part of tutorial but more of tips. This does not just apply for making Rain World mods but to general, whenever you're making something that supports translation. * When you have variables in your sentence, do not use partial phrases and Frankenstein it later with <code>string.Concat</code>. Not every language has the same grammar order of subject-verb-object as English. * Leave credits to the translators, since you¡¯re most likely getting volunteers from them. This is both good for showing gratitude to the translators and keeping the quality of the translation. The lack of credits equals a lack of responsibility. * Do not use machine translation. That usually hurts the user experience rather than enhancing it. --> == Acceptable Types == As of Config Machine <code>v1.5.1</code>, it accepts the following types and uses provided UIconfig. (Height is the pixel height that how much this ConfigEntry would use. And each entry get 20 pixeled gaps in between) {|class="wikitable" !align="right" width="23%"| type !align="center" width="29%"| UIconfig !align="right" width="23%"| Height !width="23%"| Note |- |align="right"| bool |align="center"| OpCheckBox |align="right"| 60 | |- |align="right"| byte |align="center"| OpSliderSubtle |align="right"| 90 | Range: [0, 20] |- |align="right"| uint |align="center"| OpSlider |align="right"| 90 | Range: [0, 100] |- |align="right"| int |align="center"| OpTextBox |align="right"| 60 | Accepts: Int |- |align="right"| float |align="center"| OpTextBox |align="right"| 60 | Accepts: Float |- |align="right"| string(Hex) |align="center"| OpColorPicker |align="right"| 170 | When defaultValue is Hex |- |align="right"| string |align="center"| OpTextBox |align="right"| 60 | When defaultValue is not Hex; Accepts: ASCII |- |align="right"| KeyCode |align="center"| OpKeyBinder |align="right"| 100 | |- |align="right"| enumType |align="center"| OpResourceSelector |align="right"| 60 | |- |align="right"| default |align="center"| N/A |align="right"| | Will warn the user that this plugin has ConfigEntry that’s not supported by Config Machine |} == Available UI Elements == Full list of available UI elements can be found [[ConfigMachine/Provided Elements|here]]. [[Category:Dependencies]] [[Category:Code Mods]] 4928602e3080fdd242373a73ecd41fdb72c6cbe6 User:PJB 2 169 358 2023-01-15T15:22:17Z PJB 38 create user page wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 Category:Code Mods 14 74 361 206 2023-01-27T19:37:32Z Alextabitha 44 Updated .NET version from 3.5 to 4.8 wikitext text/x-wiki Code mods are incredibly versatile. They allow for fixing bugs in the vanilla game, adding quality of life (QoL) features, and all sorts of brand new features including new creatures and gamemodes. Code mods are sometimes included in Region Packs, either as supplimentary features or dependencies of those features. To load code mods, we use a modified version of [[BepInEx]]. == Writing Code Mods == Rain World is programmed in C# with Unity, meaning that we have access to plenty of .NET and Unity oriented modding tools. RW code mods are generally written in C# and built for the .NET Framework 4.8 runtime. If you're looking to start making code mods, it's recommended that you start with [[BepInPlugins]]. You're likely to get the most support with these, they're the easiest to make, and they're very capable. Before diving into the details of writing a code mod, you'll need to [[Code Environments|set up your code environment]]. Modern Rain World code mods typically come in a few flavours... * [[BepInPlugins]] - ''the most common. They largely use a technique called hooking, which allows for many possibilities and makes for good compatibility with other mods.'' * [https://docs.bepinex.dev/articles/dev_guide/preloader_patchers.html Preloader Patchers] - ''powered by Mono.Cecil. Used to apply changes to asseblies during the preloader phase.'' Older Rain World code mods are generally: * [[Standalone Mods]] * [[Partiality Mods]] * [[MonoMod Patches]] ef92c5747ead631bc88a9ee8615ec25689a31595 Code Environments 0 126 364 363 2023-01-27T20:16:39Z Alextabitha 44 Add common reference for Unity Engine Core Module which is needed when creating BepInPlugins wikitext text/x-wiki This page contains is a guide on setting up a development environment for making code mods. == Reading Code == To mod Rain World, you need to be able to read the game's code. As it was written in C# and compiled against .NET Framework 4.8, you will need to use a decompiler to view the code. Remember that it is illegal to redistribute the game's code; decompiled copies are for your own use only. A few decompiler options are available to you, including: === dnSpy === [[File:dnspy.png|thumb|dnSpy being used to view the decompiled code of a mod's method in C#.]] '''Warning:''' in recent years, trojans have been released disguised as dnSpy, targetting security researchers. You should only download dnSpy from dnSpy's GitHub repository ([https://github.com/dnSpy/dnSpy/releases/latest dnSpy/dnSpy]). DnSpy is a .NET decompiler application that is designed to look visually similar to Visual Studio. It's popular with Rain World modders, modders of other .NET-based games, and security researchers. 32-bit and 64-bit Windows downloads can be found [https://github.com/dnSpy/dnSpy/releases/latest here]. dnSpy provides the most user convenience out of the options listed here, with handy usage analyzer and other inspection tools. It is, however, using an outdated version of decompiler backend, which causes it to choke and output invalid code in some cases (most notably, switch statements over strings). === ILSpy === ILSpy is a .NET decompiler backend. There are many frontends, often in the form of extensions for Visual Studio and Visual Studio Code. There's also a frontend built into JetBrains Rider. === ICsharpCode.Decompiler === Starting with version 2022, Visual Studio comes with its own decompiler: you can inspect classes from your reference libraries. == Writing Code == Most Rain World code modders use Visual Studio to write their code. This section will go over that, as well as a more generalized lightweight option. Please note that Visual Studio is not the only IDE out there: for example, [https://www.jetbrains.com/rider/ JetBrains Rider] is a good cross-platform choice if you have the money for it. <div class="wikitable"> <tabber> |-| Visual Studio= Visual Studio is one of the best development environments for C# and .NET in general. It comes with many useful tools, such as autocompletion AI, builtin syntax highlighting, built-in decompiler and graphical interfaces for configuring .NET projects. However, it also has several disadvantages: * '''Disk space issue''': every installation of Visual Studio occupies at least 5-6 GB on your drive, possibly more. * '''Portability''': VS is Windows-only. * '''Editor performance''': VS becomes less responsive on old machines. === Installing Visual Studio === # Download the ''installer'' for latest version of VS [https://visualstudio.microsoft.com/downloads/ here]. Run it. # From the installer, create a new install of VS. In workload selection menu, make sure you have ".NET desktop development" selected. In Individual components, search for ".NET Framework 4.8 targeting pack" and enable it too. # Start the installation, wait for it to finish. [[File:CodeEnv-VSInstaller.png|none|thumb|alt=Visual Studio installer screen|Visual Studio installer screen]] === Creating a project === When creating a project for a rain world mod, you will need to a '''class library''' targeting '''.NET Framework 4.8'''. There are some problems you may encounter on this step. * Occasionally Visual Studio refuses to display targeting Framework 4.8 as an option. The pattern is unclear. * Creating a project targeting fw4.8 from Visual Studio's GUI causes it to be made with old <code>.csproj</code> file format (msbuild 2003), which restricts some features and is generally more messy. '''Steps to tell if the project is in older format''': ** Open the file in a text editor ** If it looks like a pile of piss-soaked spaghetti and has <code>Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"</code> around the beginning, it's old. Thus it's recommended to create project files from the command line with <code>dotnet new</code>: [[File:CodeEnv-DotnetCLI.png|none|thumb|alt=Creating a project with dotnet CLI|Creating a project with dotnet CLI]] Then open the resulting .csproj in Visual Studio, double click the project name in solution structure, and change the first block to have tags with following values: === Adding references === To compile mods and access the game code, you need to add some assemblies to your project as ''references''. To do this, you can * Use <code>Project -> Add project reference...</code> in VS. * Manually add <code>Include</code>s to your .csproj. List of common required references is in the section [[#Common references]]. If you are planning to share your code at some point, it is recommended that you set up your references without using absolute paths on your PC. This can be done in few ways: * Copying the reference files to a folder inside or near the project folder. * Setting up a folder symlink from somewhere in the project to a reference dir. On Windows, you can use [https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink mklink /J] from command prompt. In either case, you should [https://git-scm.com/docs/gitignore gitignore] references if they happen to be in a repo to avoid redistributing others' code. === Building === After you've wrote something, you will naturally want to run it and see if it works. As of now, there is no way of attaching a debugger to Rain World process, and version of Mono packed with the game does not load .pdb files. Thus you should always build your mods on Release configuration, even if you're mid-development. To load a mod into the game, you need to copy its assembly into respective BepInEx active folder (<code>BepInEx/plugins/</code> unless you are making an [[MonoMod Patches|mmpatch]]). You can automate this step by using a build event: * In Project properties view in VS, find Build Events, and into Post-build insert one of these: ** Unconditional build event with hardcoded destination: <code>copy /Y "$(TargetPath)" "Path/to/your/plugins/folder/here"</code> ** Copies files into a path defined by environment variable <code>RWMods</code> (if it exists): <code>if defined RWMods (copy /Y "$(TargetPath)" "%RWMods%")</code> By default, building a project copies most of its dependencies to the build destination (<code>bin/release/</code>). You can prevent it by selecting desired references in solution explorer, opening properties dock and setting <code>Copy Local</code> to <code>No</code>: [[File:CodeEnv-copyLocal.png|thumb|none|alt=Disabling Copy Local|Disabling Copy Local]] |-| Simple code editor + dotnet CLI= {{todo|target=tab}} Another option is using a simpler code editor (such as [https://code.visualstudio.com/ Visual Studio Code] with a c# extension, or even [https://notepad-plus-plus.org/downloads/ notepad++] if you enjoy torture). This setup lacks advanced functions of Visual Studio, but allows you to write and build on non-windows systems. === Installing .NET SDK === Download the latest .NET SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/6.0 6.0.400]) and install it. New SDKs are able to build projects for old runtimes. Use the SDK via <code>dotnet</code> from the command line. Full docs for the command can be found [https://docs.microsoft.com/en-us/dotnet/core/tools/ here]. === Creating a project === Use <code>dotnet new classlib -n [projectName]</code> to create a project. After it's there, open the .csproj file and edit the first <code>PropertyGroup</code> according to [[#csproj PropertyGroup]] section. After this is done, you can start writing. Any '''.cs''' file put into the project folder or one of its subfolders is automatically included. === Adding references === You can add a reference to the project by including <pre><nowiki> <Reference Include="path/to/Assembly.dll"> </Reference> </nowiki></pre> in an <code>ItemGroup</code>. Wildcards and relative paths are supported. To disable copying of references to target directory, change the include tag to look like the following: <pre><nowiki> <Reference Include="libs/*.dll"> <Private>false</Private> </Reference> </nowiki></pre> === Building === Use <code>dotnet build</code> in your project directory to build your project. Output goes into <code>bin/[Debug//Release]/</code> depending on your current configuration. </tabber> </div> ==== Common references ==== For all mods, it is a good idea to reference: {|class="wikitable" |- ! Assembly !! Contains !! Notes |- | RainWorld_Data/Managed/AssemblyCSharp.dll || All of the vanilla game code || Use [https://github.com/Reinms/Stubber-Publicizer this tool] to remove accessibility restrictions |- | RainWorld_Data/Managed/UnityEngine.dll || Unity API methods |- | RainWorld_Data/Managed/UnityEngine.CoreModule.dll || Core Unity methods |- | BepInEx/core/BepInEx.dll || [[BepInEx]] api |- | BepInEx/plugins/HOOKS-Assembly-CSharp.dll || Hookgen events for methods in Assembly-CSharp for easily attaching code |- | BepInEx/core/MonoMod.RuntimeDetour || Classes and methods necessary for applying manual detours/hooks |- | BepInEx/core/MonoMod.Utils.dll || Classes and methods necessary for applying IL hooks, as well as some additional functionality |} Additionally, if you want to use a dependency mod, you will likely need to reference it too. ==== csproj PropertyGroup ==== When creating a csproj file from CLI, you will need to edit it to have following values: {| class="wikitable" |- ! Tag !! Value !! Comment |- | TargetFramework || net48 || Framework version |- | ImplicitUsings || disable || Can not be used on .NET Framework 4.8 only 6+ |- | Nullable || disable || Toggles some compile-time null checking rules.<br />You can keep it enabled,<br />but it won't apply to the game code. |- | LangVersion || latest || Without this tag, language version stays at C#7.3<br />Later language versions include some handy features. |} ==== csproj structure ==== {{todo}} [[File:CodeEnv-csprojStructure.png|thumb|none|alt=Visual example|Visual example]] Official reference for .NET SDK .csproj format can be found [https://docs.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props here]. === Testing and Debugging === {{todo}} As mentioned, attaching a debugger to the game is currently not an option. This sections will contain several tips on mitigating the pain. * You can enable a separate console window for BepInEx output in <code>BepInEx/config/bepinex.cfg</code>. * From a [[BepInPlugins|BepInEx plugin]], use <code>Logger</code> property. If you need to lend access to your logger to different class, use something like: <syntaxhighlight lang="csharp"> public class MyPlugin : Baseunityplugin { public MyPlugin() { __me = new(this); } //using WeakReference to allow garbage collection private static WeakReference __me; public static MyPlugin ME => __me?.target as MyPlugin; //wrapper property. If you don't need a static member, just do this and pass plugin instance around. public ManualLogSource Logger_p => Logger; } //... MyPlugin.ME.Logger_p.Log(); </syntaxhighlight> * [https://github.com/casheww/RW-ToolBox/releases/latest This plugin] by casheww might help you with specific tasks == Misc tips and trivia == {{todo}} * You can use Embedded Resources to include arbitrary data, such as text files or images, with your assembly. To do this, select a file in Solution explorer, open Properties dock, and set <code>Build action</code> to <code>Embedded Resource</code>. You can retrieve the resources as <code>byte[]</code>s using methods '''GetManifestResourceNames''' and '''GetManifestResourceStream''' on <code>System.Reflection.Assembly</code> instance. [[Category:Code Mods]] dab72fcafcb28c15c30c9b09b75f357af356a0e5 366 364 2023-01-27T21:55:51Z Alextabitha 44 Changed reference to use BepInEx utils assembly file which removes any accessibility issues wikitext text/x-wiki This page contains is a guide on setting up a development environment for making code mods. == Reading Code == To mod Rain World, you need to be able to read the game's code. As it was written in C# and compiled against .NET Framework 4.8, you will need to use a decompiler to view the code. Remember that it is illegal to redistribute the game's code; decompiled copies are for your own use only. A few decompiler options are available to you, including: === dnSpy === [[File:dnspy.png|thumb|dnSpy being used to view the decompiled code of a mod's method in C#.]] '''Warning:''' in recent years, trojans have been released disguised as dnSpy, targetting security researchers. You should only download dnSpy from dnSpy's GitHub repository ([https://github.com/dnSpy/dnSpy/releases/latest dnSpy/dnSpy]). DnSpy is a .NET decompiler application that is designed to look visually similar to Visual Studio. It's popular with Rain World modders, modders of other .NET-based games, and security researchers. 32-bit and 64-bit Windows downloads can be found [https://github.com/dnSpy/dnSpy/releases/latest here]. dnSpy provides the most user convenience out of the options listed here, with handy usage analyzer and other inspection tools. It is, however, using an outdated version of decompiler backend, which causes it to choke and output invalid code in some cases (most notably, switch statements over strings). === ILSpy === ILSpy is a .NET decompiler backend. There are many frontends, often in the form of extensions for Visual Studio and Visual Studio Code. There's also a frontend built into JetBrains Rider. === ICsharpCode.Decompiler === Starting with version 2022, Visual Studio comes with its own decompiler: you can inspect classes from your reference libraries. == Writing Code == Most Rain World code modders use Visual Studio to write their code. This section will go over that, as well as a more generalized lightweight option. Please note that Visual Studio is not the only IDE out there: for example, [https://www.jetbrains.com/rider/ JetBrains Rider] is a good cross-platform choice if you have the money for it. <div class="wikitable"> <tabber> |-| Visual Studio= Visual Studio is one of the best development environments for C# and .NET in general. It comes with many useful tools, such as autocompletion AI, builtin syntax highlighting, built-in decompiler and graphical interfaces for configuring .NET projects. However, it also has several disadvantages: * '''Disk space issue''': every installation of Visual Studio occupies at least 5-6 GB on your drive, possibly more. * '''Portability''': VS is Windows-only. * '''Editor performance''': VS becomes less responsive on old machines. === Installing Visual Studio === # Download the ''installer'' for latest version of VS [https://visualstudio.microsoft.com/downloads/ here]. Run it. # From the installer, create a new install of VS. In workload selection menu, make sure you have ".NET desktop development" selected. In Individual components, search for ".NET Framework 4.8 targeting pack" and enable it too. # Start the installation, wait for it to finish. [[File:CodeEnv-VSInstaller.png|none|thumb|alt=Visual Studio installer screen|Visual Studio installer screen]] === Creating a project === When creating a project for a rain world mod, you will need to a '''class library''' targeting '''.NET Framework 4.8'''. There are some problems you may encounter on this step. * Occasionally Visual Studio refuses to display targeting Framework 4.8 as an option. The pattern is unclear. * Creating a project targeting fw4.8 from Visual Studio's GUI causes it to be made with old <code>.csproj</code> file format (msbuild 2003), which restricts some features and is generally more messy. '''Steps to tell if the project is in older format''': ** Open the file in a text editor ** If it looks like a pile of piss-soaked spaghetti and has <code>Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"</code> around the beginning, it's old. Thus it's recommended to create project files from the command line with <code>dotnet new</code>: [[File:CodeEnv-DotnetCLI.png|none|thumb|alt=Creating a project with dotnet CLI|Creating a project with dotnet CLI]] Then open the resulting .csproj in Visual Studio, double click the project name in solution structure, and change the first block to have tags with following values: === Adding references === To compile mods and access the game code, you need to add some assemblies to your project as ''references''. To do this, you can * Use <code>Project -> Add project reference...</code> in VS. * Manually add <code>Include</code>s to your .csproj. List of common required references is in the section [[#Common references]]. If you are planning to share your code at some point, it is recommended that you set up your references without using absolute paths on your PC. This can be done in few ways: * Copying the reference files to a folder inside or near the project folder. * Setting up a folder symlink from somewhere in the project to a reference dir. On Windows, you can use [https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink mklink /J] from command prompt. In either case, you should [https://git-scm.com/docs/gitignore gitignore] references if they happen to be in a repo to avoid redistributing others' code. === Building === After you've wrote something, you will naturally want to run it and see if it works. As of now, there is no way of attaching a debugger to Rain World process, and version of Mono packed with the game does not load .pdb files. Thus you should always build your mods on Release configuration, even if you're mid-development. To load a mod into the game, you need to copy its assembly into respective BepInEx active folder (<code>BepInEx/plugins/</code> unless you are making an [[MonoMod Patches|mmpatch]]). You can automate this step by using a build event: * In Project properties view in VS, find Build Events, and into Post-build insert one of these: ** Unconditional build event with hardcoded destination: <code>copy /Y "$(TargetPath)" "Path/to/your/plugins/folder/here"</code> ** Copies files into a path defined by environment variable <code>RWMods</code> (if it exists): <code>if defined RWMods (copy /Y "$(TargetPath)" "%RWMods%")</code> By default, building a project copies most of its dependencies to the build destination (<code>bin/release/</code>). You can prevent it by selecting desired references in solution explorer, opening properties dock and setting <code>Copy Local</code> to <code>No</code>: [[File:CodeEnv-copyLocal.png|thumb|none|alt=Disabling Copy Local|Disabling Copy Local]] |-| Simple code editor + dotnet CLI= {{todo|target=tab}} Another option is using a simpler code editor (such as [https://code.visualstudio.com/ Visual Studio Code] with a c# extension, or even [https://notepad-plus-plus.org/downloads/ notepad++] if you enjoy torture). This setup lacks advanced functions of Visual Studio, but allows you to write and build on non-windows systems. === Installing .NET SDK === Download the latest .NET SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/6.0 6.0.400]) and install it. New SDKs are able to build projects for old runtimes. Use the SDK via <code>dotnet</code> from the command line. Full docs for the command can be found [https://docs.microsoft.com/en-us/dotnet/core/tools/ here]. === Creating a project === Use <code>dotnet new classlib -n [projectName]</code> to create a project. After it's there, open the .csproj file and edit the first <code>PropertyGroup</code> according to [[#csproj PropertyGroup]] section. After this is done, you can start writing. Any '''.cs''' file put into the project folder or one of its subfolders is automatically included. === Adding references === You can add a reference to the project by including <pre><nowiki> <Reference Include="path/to/Assembly.dll"> </Reference> </nowiki></pre> in an <code>ItemGroup</code>. Wildcards and relative paths are supported. To disable copying of references to target directory, change the include tag to look like the following: <pre><nowiki> <Reference Include="libs/*.dll"> <Private>false</Private> </Reference> </nowiki></pre> === Building === Use <code>dotnet build</code> in your project directory to build your project. Output goes into <code>bin/[Debug//Release]/</code> depending on your current configuration. </tabber> </div> ==== Common references ==== For all mods, it is a good idea to reference: {|class="wikitable" |- ! Assembly !! Contains |- | BepInEx/utils/PUBLIC-Assembly-CSharp.dll || All of the vanilla game code with access modifiers changed to stop any issues when modding |- | RainWorld_Data/Managed/UnityEngine.dll || Unity API methods |- | RainWorld_Data/Managed/UnityEngine.CoreModule.dll || Core Unity methods |- | BepInEx/core/BepInEx.dll || [[BepInEx]] api |- | BepInEx/plugins/HOOKS-Assembly-CSharp.dll || Hookgen events for methods in Assembly-CSharp for easily attaching code |- | BepInEx/core/MonoMod.RuntimeDetour || Classes and methods necessary for applying manual detours/hooks |- | BepInEx/core/MonoMod.Utils.dll || Classes and methods necessary for applying IL hooks, as well as some additional functionality |} Additionally, if you want to use a dependency mod, you will likely need to reference it too. ==== csproj PropertyGroup ==== When creating a csproj file from CLI, you will need to edit it to have following values: {| class="wikitable" |- ! Tag !! Value !! Comment |- | TargetFramework || net48 || Framework version |- | ImplicitUsings || disable || Can not be used on .NET Framework 4.8 only 6+ |- | Nullable || disable || Toggles some compile-time null checking rules.<br />You can keep it enabled,<br />but it won't apply to the game code. |- | LangVersion || latest || Without this tag, language version stays at C#7.3<br />Later language versions include some handy features. |} ==== csproj structure ==== {{todo}} [[File:CodeEnv-csprojStructure.png|thumb|none|alt=Visual example|Visual example]] Official reference for .NET SDK .csproj format can be found [https://docs.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props here]. === Testing and Debugging === {{todo}} As mentioned, attaching a debugger to the game is currently not an option. This sections will contain several tips on mitigating the pain. * You can enable a separate console window for BepInEx output in <code>BepInEx/config/bepinex.cfg</code>. * From a [[BepInPlugins|BepInEx plugin]], use <code>Logger</code> property. If you need to lend access to your logger to different class, use something like: <syntaxhighlight lang="csharp"> public class MyPlugin : Baseunityplugin { public MyPlugin() { __me = new(this); } //using WeakReference to allow garbage collection private static WeakReference __me; public static MyPlugin ME => __me?.target as MyPlugin; //wrapper property. If you don't need a static member, just do this and pass plugin instance around. public ManualLogSource Logger_p => Logger; } //... MyPlugin.ME.Logger_p.Log(); </syntaxhighlight> * [https://github.com/casheww/RW-ToolBox/releases/latest This plugin] by casheww might help you with specific tasks == Misc tips and trivia == {{todo}} * You can use Embedded Resources to include arbitrary data, such as text files or images, with your assembly. To do this, select a file in Solution explorer, open Properties dock, and set <code>Build action</code> to <code>Embedded Resource</code>. You can retrieve the resources as <code>byte[]</code>s using methods '''GetManifestResourceNames''' and '''GetManifestResourceStream''' on <code>System.Reflection.Assembly</code> instance. [[Category:Code Mods]] 188f5cf493b6d373c2b9f51276ed285f631fd7ad 370 366 2023-01-31T10:21:11Z Cashewww 2 /* ILSpy */ wikitext text/x-wiki This page contains is a guide on setting up a development environment for making code mods. == Reading Code == To mod Rain World, you need to be able to read the game's code. As it was written in C# and compiled against .NET Framework 4.8, you will need to use a decompiler to view the code. Remember that it is illegal to redistribute the game's code; decompiled copies are for your own use only. A few decompiler options are available to you, including: === dnSpy === [[File:dnspy.png|thumb|dnSpy being used to view the decompiled code of a mod's method in C#.]] '''Warning:''' in recent years, trojans have been released disguised as dnSpy, targetting security researchers. You should only download dnSpy from dnSpy's GitHub repository ([https://github.com/dnSpy/dnSpy/releases/latest dnSpy/dnSpy]). DnSpy is a .NET decompiler application that is designed to look visually similar to Visual Studio. It's popular with Rain World modders, modders of other .NET-based games, and security researchers. 32-bit and 64-bit Windows downloads can be found [https://github.com/dnSpy/dnSpy/releases/latest here]. dnSpy provides the most user convenience out of the options listed here, with handy usage analyzer and other inspection tools. It is, however, using an outdated version of decompiler backend, which causes it to choke and output invalid code in some cases (most notably, switch statements over strings). === ILSpy === ILSpy is a .NET decompiler backend. There are many frontends, often in the form of extensions for Visual Studio and Visual Studio Code. There's also a frontend built into JetBrains Rider. For Linux users who don't have a JetBrains license, frontends like [https://github.com/icsharpcode/AvaloniaILSpy/releases AvaloniaILSpy] are available. === ICsharpCode.Decompiler === Starting with version 2022, Visual Studio comes with its own decompiler: you can inspect classes from your reference libraries. == Writing Code == Most Rain World code modders use Visual Studio to write their code. This section will go over that, as well as a more generalized lightweight option. Please note that Visual Studio is not the only IDE out there: for example, [https://www.jetbrains.com/rider/ JetBrains Rider] is a good cross-platform choice if you have the money for it. <div class="wikitable"> <tabber> |-| Visual Studio= Visual Studio is one of the best development environments for C# and .NET in general. It comes with many useful tools, such as autocompletion AI, builtin syntax highlighting, built-in decompiler and graphical interfaces for configuring .NET projects. However, it also has several disadvantages: * '''Disk space issue''': every installation of Visual Studio occupies at least 5-6 GB on your drive, possibly more. * '''Portability''': VS is Windows-only. * '''Editor performance''': VS becomes less responsive on old machines. === Installing Visual Studio === # Download the ''installer'' for latest version of VS [https://visualstudio.microsoft.com/downloads/ here]. Run it. # From the installer, create a new install of VS. In workload selection menu, make sure you have ".NET desktop development" selected. In Individual components, search for ".NET Framework 4.8 targeting pack" and enable it too. # Start the installation, wait for it to finish. [[File:CodeEnv-VSInstaller.png|none|thumb|alt=Visual Studio installer screen|Visual Studio installer screen]] === Creating a project === When creating a project for a rain world mod, you will need to a '''class library''' targeting '''.NET Framework 4.8'''. There are some problems you may encounter on this step. * Occasionally Visual Studio refuses to display targeting Framework 4.8 as an option. The pattern is unclear. * Creating a project targeting fw4.8 from Visual Studio's GUI causes it to be made with old <code>.csproj</code> file format (msbuild 2003), which restricts some features and is generally more messy. '''Steps to tell if the project is in older format''': ** Open the file in a text editor ** If it looks like a pile of piss-soaked spaghetti and has <code>Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"</code> around the beginning, it's old. Thus it's recommended to create project files from the command line with <code>dotnet new</code>: [[File:CodeEnv-DotnetCLI.png|none|thumb|alt=Creating a project with dotnet CLI|Creating a project with dotnet CLI]] Then open the resulting .csproj in Visual Studio, double click the project name in solution structure, and change the first block to have tags with following values: === Adding references === To compile mods and access the game code, you need to add some assemblies to your project as ''references''. To do this, you can * Use <code>Project -> Add project reference...</code> in VS. * Manually add <code>Include</code>s to your .csproj. List of common required references is in the section [[#Common references]]. If you are planning to share your code at some point, it is recommended that you set up your references without using absolute paths on your PC. This can be done in few ways: * Copying the reference files to a folder inside or near the project folder. * Setting up a folder symlink from somewhere in the project to a reference dir. On Windows, you can use [https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink mklink /J] from command prompt. In either case, you should [https://git-scm.com/docs/gitignore gitignore] references if they happen to be in a repo to avoid redistributing others' code. === Building === After you've wrote something, you will naturally want to run it and see if it works. As of now, there is no way of attaching a debugger to Rain World process, and version of Mono packed with the game does not load .pdb files. Thus you should always build your mods on Release configuration, even if you're mid-development. To load a mod into the game, you need to copy its assembly into respective BepInEx active folder (<code>BepInEx/plugins/</code> unless you are making an [[MonoMod Patches|mmpatch]]). You can automate this step by using a build event: * In Project properties view in VS, find Build Events, and into Post-build insert one of these: ** Unconditional build event with hardcoded destination: <code>copy /Y "$(TargetPath)" "Path/to/your/plugins/folder/here"</code> ** Copies files into a path defined by environment variable <code>RWMods</code> (if it exists): <code>if defined RWMods (copy /Y "$(TargetPath)" "%RWMods%")</code> By default, building a project copies most of its dependencies to the build destination (<code>bin/release/</code>). You can prevent it by selecting desired references in solution explorer, opening properties dock and setting <code>Copy Local</code> to <code>No</code>: [[File:CodeEnv-copyLocal.png|thumb|none|alt=Disabling Copy Local|Disabling Copy Local]] |-| Simple code editor + dotnet CLI= {{todo|target=tab}} Another option is using a simpler code editor (such as [https://code.visualstudio.com/ Visual Studio Code] with a c# extension, or even [https://notepad-plus-plus.org/downloads/ notepad++] if you enjoy torture). This setup lacks advanced functions of Visual Studio, but allows you to write and build on non-windows systems. === Installing .NET SDK === Download the latest .NET SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/6.0 6.0.400]) and install it. New SDKs are able to build projects for old runtimes. Use the SDK via <code>dotnet</code> from the command line. Full docs for the command can be found [https://docs.microsoft.com/en-us/dotnet/core/tools/ here]. === Creating a project === Use <code>dotnet new classlib -n [projectName]</code> to create a project. After it's there, open the .csproj file and edit the first <code>PropertyGroup</code> according to [[#csproj PropertyGroup]] section. After this is done, you can start writing. Any '''.cs''' file put into the project folder or one of its subfolders is automatically included. === Adding references === You can add a reference to the project by including <pre><nowiki> <Reference Include="path/to/Assembly.dll"> </Reference> </nowiki></pre> in an <code>ItemGroup</code>. Wildcards and relative paths are supported. To disable copying of references to target directory, change the include tag to look like the following: <pre><nowiki> <Reference Include="libs/*.dll"> <Private>false</Private> </Reference> </nowiki></pre> === Building === Use <code>dotnet build</code> in your project directory to build your project. Output goes into <code>bin/[Debug//Release]/</code> depending on your current configuration. </tabber> </div> ==== Common references ==== For all mods, it is a good idea to reference: {|class="wikitable" |- ! Assembly !! Contains |- | BepInEx/utils/PUBLIC-Assembly-CSharp.dll || All of the vanilla game code with access modifiers changed to stop any issues when modding |- | RainWorld_Data/Managed/UnityEngine.dll || Unity API methods |- | RainWorld_Data/Managed/UnityEngine.CoreModule.dll || Core Unity methods |- | BepInEx/core/BepInEx.dll || [[BepInEx]] api |- | BepInEx/plugins/HOOKS-Assembly-CSharp.dll || Hookgen events for methods in Assembly-CSharp for easily attaching code |- | BepInEx/core/MonoMod.RuntimeDetour || Classes and methods necessary for applying manual detours/hooks |- | BepInEx/core/MonoMod.Utils.dll || Classes and methods necessary for applying IL hooks, as well as some additional functionality |} Additionally, if you want to use a dependency mod, you will likely need to reference it too. ==== csproj PropertyGroup ==== When creating a csproj file from CLI, you will need to edit it to have following values: {| class="wikitable" |- ! Tag !! Value !! Comment |- | TargetFramework || net48 || Framework version |- | ImplicitUsings || disable || Can not be used on .NET Framework 4.8 only 6+ |- | Nullable || disable || Toggles some compile-time null checking rules.<br />You can keep it enabled,<br />but it won't apply to the game code. |- | LangVersion || latest || Without this tag, language version stays at C#7.3<br />Later language versions include some handy features. |} ==== csproj structure ==== {{todo}} [[File:CodeEnv-csprojStructure.png|thumb|none|alt=Visual example|Visual example]] Official reference for .NET SDK .csproj format can be found [https://docs.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props here]. === Testing and Debugging === {{todo}} As mentioned, attaching a debugger to the game is currently not an option. This sections will contain several tips on mitigating the pain. * You can enable a separate console window for BepInEx output in <code>BepInEx/config/bepinex.cfg</code>. * From a [[BepInPlugins|BepInEx plugin]], use <code>Logger</code> property. If you need to lend access to your logger to different class, use something like: <syntaxhighlight lang="csharp"> public class MyPlugin : Baseunityplugin { public MyPlugin() { __me = new(this); } //using WeakReference to allow garbage collection private static WeakReference __me; public static MyPlugin ME => __me?.target as MyPlugin; //wrapper property. If you don't need a static member, just do this and pass plugin instance around. public ManualLogSource Logger_p => Logger; } //... MyPlugin.ME.Logger_p.Log(); </syntaxhighlight> * [https://github.com/casheww/RW-ToolBox/releases/latest This plugin] by casheww might help you with specific tasks == Misc tips and trivia == {{todo}} * You can use Embedded Resources to include arbitrary data, such as text files or images, with your assembly. To do this, select a file in Solution explorer, open Properties dock, and set <code>Build action</code> to <code>Embedded Resource</code>. You can retrieve the resources as <code>byte[]</code>s using methods '''GetManifestResourceNames''' and '''GetManifestResourceStream''' on <code>System.Reflection.Assembly</code> instance. [[Category:Code Mods]] 5a8affd7f49825864d749006025facf51d4c6b26 371 370 2023-02-03T02:14:41Z Dual 37 wikitext text/x-wiki This page contains is a guide on setting up a development environment for making code mods. == Reading Code == To mod Rain World, you need to be able to read the game's code. As it was written in C# and compiled against .NET Framework 4.8, you will need to use a decompiler to view the code. Remember that it is illegal to redistribute the game's code; decompiled copies are for your own use only. A few decompiler options are available to you, including: === dnSpy === [[File:dnspy.png|thumb|dnSpy being used to view the decompiled code of a mod's method in C#.]] '''Warning:''' in recent years, trojans have been released disguised as dnSpy, targetting security researchers. You should only download dnSpy from dnSpy's GitHub repository ([https://github.com/dnSpy/dnSpy/releases/latest dnSpy/dnSpy]). DnSpy is a .NET decompiler application that is designed to look visually similar to Visual Studio. It's popular with Rain World modders, modders of other .NET-based games, and security researchers. 32-bit and 64-bit Windows downloads can be found [https://github.com/dnSpy/dnSpy/releases/latest here]. dnSpy provides the most user convenience out of the options listed here, with handy usage analyzer and other inspection tools. It is, however, using an outdated version of decompiler backend, which causes it to choke and output invalid code in some cases (most notably, switch statements over strings). === ILSpy === ILSpy is a .NET decompiler backend. There are many frontends, often in the form of extensions for Visual Studio and Visual Studio Code. There's also a frontend built into JetBrains Rider. For Linux users who don't have a JetBrains license, frontends like [https://github.com/icsharpcode/AvaloniaILSpy/releases AvaloniaILSpy] are available. === ICsharpCode.Decompiler === Starting with version 2022, Visual Studio comes with its own decompiler: you can inspect classes from your reference libraries. == Writing Code == Most Rain World code modders use Visual Studio to write their code. This section will go over that, as well as a more generalized lightweight option. Please note that Visual Studio is not the only IDE out there: for example, [https://www.jetbrains.com/rider/ JetBrains Rider] is a good cross-platform choice if you have the money for it. <div class="wikitable"> <tabber> |-| Visual Studio= Visual Studio is one of the best development environments for C# and .NET in general. It comes with many useful tools, such as autocompletion AI, builtin syntax highlighting, built-in decompiler and graphical interfaces for configuring .NET projects. However, it also has several disadvantages: * '''Disk space issue''': every installation of Visual Studio occupies at least 5-6 GB on your drive, possibly more. * '''Portability''': VS is Windows-only. * '''Editor performance''': VS becomes less responsive on old machines. === Installing Visual Studio === # Download the ''installer'' for latest version of VS [https://visualstudio.microsoft.com/downloads/ here]. Run it. # From the installer, create a new install of VS. In workload selection menu, make sure you have ".NET desktop development" selected. In Individual components, search for ".NET Framework 4.8 targeting pack" and enable it too. # Start the installation, wait for it to finish. [[File:CodeEnv-VSInstaller.png|none|thumb|alt=Visual Studio installer screen|Visual Studio installer screen]] === Creating a project === When creating a project for a rain world mod, you will need to a '''class library''' targeting '''.NET Framework 4.8'''. There are some problems you may encounter on this step. * Occasionally Visual Studio refuses to display targeting Framework 4.8 as an option. The pattern is unclear. * Creating a project targeting fw4.8 from Visual Studio's GUI causes it to be made with old <code>.csproj</code> file format (msbuild 2003), which restricts some features and is generally more messy. '''Steps to tell if the project is in older format''': ** Open the file in a text editor ** If it looks like a pile of piss-soaked spaghetti and has <code>Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"</code> around the beginning, it's old. Thus it's recommended to create project files from the command line with <code>dotnet new</code>: [[File:CodeEnv-DotnetCLI.png|none|thumb|alt=Creating a project with dotnet CLI|Creating a project with dotnet CLI]] Then open the resulting .csproj in Visual Studio, double click the project name in solution structure, and change the first block to have tags with following values: === Adding references === To compile mods and access the game code, you need to add some assemblies to your project as ''references''. To do this, you can * Use <code>Project -> Add project reference...</code> in VS. * Manually add <code>Include</code>s to your .csproj. List of common required references is in the section [[#Common references]]. If you are planning to share your code at some point, it is recommended that you set up your references without using absolute paths on your PC. This can be done in few ways: * Copying the reference files to a folder inside or near the project folder. * Setting up a folder symlink from somewhere in the project to a reference dir. On Windows, you can use [https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink mklink /J] from command prompt. In either case, you should [https://git-scm.com/docs/gitignore gitignore] references if they happen to be in a repo to avoid redistributing others' code. === Building === After you've wrote something, you will naturally want to run it and see if it works. As of now, there is no way of attaching a debugger to Rain World process, and version of Mono packed with the game does not load .pdb files. Thus you should always build your mods on Release configuration, even if you're mid-development. To load a mod into the game, you need to copy its assembly into respective BepInEx active folder (<code>BepInEx/plugins/</code> unless you are making an [[MonoMod Patches|mmpatch]]). You can automate this step by using a build event: * In Project properties view in VS, find Build Events, and into Post-build insert one of these: ** Unconditional build event with hardcoded destination: <code>copy /Y "$(TargetPath)" "Path/to/your/plugins/folder/here"</code> ** Copies files into a path defined by environment variable <code>RWMods</code> (if it exists): <code>if defined RWMods (copy /Y "$(TargetPath)" "%RWMods%")</code> By default, building a project copies most of its dependencies to the build destination (<code>bin/release/</code>). You can prevent it by selecting desired references in solution explorer, opening properties dock and setting <code>Copy Local</code> to <code>No</code>: [[File:CodeEnv-copyLocal.png|thumb|none|alt=Disabling Copy Local|Disabling Copy Local]] |-| Simple code editor + dotnet CLI= {{todo|target=tab}} Another option is using a simpler code editor (such as [https://code.visualstudio.com/ Visual Studio Code] with a c# extension, or even [https://notepad-plus-plus.org/downloads/ notepad++] if you enjoy torture). This setup lacks advanced functions of Visual Studio, but allows you to write and build on non-windows systems. === Installing .NET SDK === Download the latest .NET SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/6.0 6.0.400]) and install it. New SDKs are able to build projects for old runtimes. Use the SDK via <code>dotnet</code> from the command line. Full docs for the command can be found [https://docs.microsoft.com/en-us/dotnet/core/tools/ here]. === Creating a project === Use <code>dotnet new classlib -n [projectName]</code> to create a project. After it's there, open the .csproj file and edit the first <code>PropertyGroup</code> according to [[#csproj PropertyGroup]] section. After this is done, you can start writing. Any '''.cs''' file put into the project folder or one of its subfolders is automatically included. === Adding references === You can add a reference to the project by including <pre><nowiki> <Reference Include="path/to/Assembly.dll"> </Reference> </nowiki></pre> in an <code>ItemGroup</code>. Wildcards and relative paths are supported. To disable copying of references to target directory, change the include tag to look like the following: <pre><nowiki> <Reference Include="libs/*.dll"> <Private>false</Private> </Reference> </nowiki></pre> === Building === Use <code>dotnet build</code> in your project directory to build your project. Output goes into <code>bin/[Debug//Release]/</code> depending on your current configuration. </tabber> </div> ==== Common references ==== For all mods, it is a good idea to reference: {|class="wikitable" |- ! Assembly !! Contains |- | BepInEx/utils/PUBLIC-Assembly-CSharp.dll || All of the vanilla game code with access modifiers changed to stop any issues when modding |- | RainWorld_Data/Managed/UnityEngine.dll || Unity API methods |- | RainWorld_Data/Managed/UnityEngine.CoreModule.dll || Core Unity methods |- | BepInEx/core/BepInEx.dll || [[BepInEx]] api |- | BepInEx/plugins/HOOKS-Assembly-CSharp.dll || Hookgen events for methods in Assembly-CSharp for easily attaching code |- | BepInEx/core/MonoMod.RuntimeDetour || Classes and methods necessary for applying manual detours/hooks |- | BepInEx/core/MonoMod.Utils.dll || Classes and methods necessary for applying IL hooks, as well as some additional functionality |} Additionally, if you want to use a dependency mod, you will likely need to reference it too. ==== csproj PropertyGroup ==== When creating a csproj file from CLI, you will need to edit it to have following values: {| class="wikitable" |- ! Tag !! Value !! Comment |- | TargetFramework || net48 || Framework version |- | ImplicitUsings || disable || Can not be used on .NET Framework 4.8 only 6+ |- | Nullable || disable || Toggles some compile-time null checking rules.<br />You can keep it enabled,<br />but it won't apply to the game code. |- | LangVersion || latest || Without this tag, language version stays at C#7.3<br />Later language versions include some handy features. |} ==== csproj structure ==== {{todo}} [[File:CodeEnv-csprojStructure.png|thumb|none|alt=Visual example|Visual example]] Official reference for .NET SDK .csproj format can be found [https://docs.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props here]. === Testing and Debugging === {{todo}} As mentioned, attaching a debugger to the game is currently not an option. This sections will contain several tips on mitigating the pain. * You can enable a separate console window for BepInEx output in <code>BepInEx/config/bepinex.cfg</code>. * From a [[BepInPlugins|BepInEx plugin]], use <code>Logger</code> property. If you need to use your logger in another class, include the following in your plugin class: <syntaxhighlight lang="csharp"> public static new ManualLogSource Logger { get; private set; } public void OnEnable() { Logger = base.Logger; } </syntaxhighlight> * [https://github.com/casheww/RW-ToolBox/releases/latest This plugin] by casheww might help you with specific tasks == Misc tips and trivia == {{todo}} * You can use Embedded Resources to include arbitrary data, such as text files or images, with your assembly. To do this, select a file in Solution explorer, open Properties dock, and set <code>Build action</code> to <code>Embedded Resource</code>. You can retrieve the resources as <code>byte[]</code>s using methods '''GetManifestResourceNames''' and '''GetManifestResourceStream''' on <code>System.Reflection.Assembly</code> instance. [[Category:Code Mods]] 64839dc6c201a996ea81bb38ceb0d7c51a0d1b7f 406 371 2023-03-30T20:36:33Z Thalber 3 wikitext text/x-wiki This page contains is a guide on setting up a development environment for making code mods. == Reading Code == To mod Rain World, you need to be able to read the game's code. As it was written in C# and compiled against .NET Framework 4.8, you will need to use a decompiler to view the code. Remember that it is illegal to redistribute the game's code; decompiled copies are for your own use only. A few decompiler options are available to you, including: === dnSpy === [[File:dnspy.png|thumb|dnSpy being used to view the decompiled code of a mod's method in C#.]] '''Warning:''' in recent years, trojans have been released disguised as dnSpy, targetting security researchers. You should only download dnSpy from dnSpy's GitHub repository ([https://github.com/dnSpy/dnSpy/releases/latest dnSpy/dnSpy]). DnSpy is a .NET decompiler application that is designed to look visually similar to Visual Studio. It's popular with Rain World modders, modders of other .NET-based games, and security researchers. 32-bit and 64-bit Windows downloads can be found [https://github.com/dnSpy/dnSpy/releases/latest here]. dnSpy provides the most user convenience out of the options listed here, with handy usage analyzer and other inspection tools. It is, however, using an outdated version of decompiler backend, which causes it to choke and output invalid code in some cases (most notably, switch statements over strings). === ILSpy === ILSpy is a .NET decompiler backend. There are many frontends, often in the form of extensions for Visual Studio and Visual Studio Code. There's also a frontend built into JetBrains Rider. For Linux users who don't have a JetBrains license, frontends like [https://github.com/icsharpcode/AvaloniaILSpy/releases AvaloniaILSpy] are available. === ICsharpCode.Decompiler === Starting with version 2022, Visual Studio comes with its own decompiler: you can inspect classes from your reference libraries. == Writing Code == Most Rain World code modders use Visual Studio to write their code. This section will go over that, as well as a more generalized lightweight option. Please note that Visual Studio is not the only IDE out there: for example, [https://www.jetbrains.com/rider/ JetBrains Rider] is a good cross-platform choice if you have the money for it. <div class="wikitable"> <tabber> |-| Visual Studio= Visual Studio is one of the best development environments for C# and .NET in general. It comes with many useful tools, such as autocompletion AI, builtin syntax highlighting, built-in decompiler and graphical interfaces for configuring .NET projects. However, it also has several disadvantages: * '''Disk space issue''': every installation of Visual Studio occupies at least 5-6 GB on your drive, possibly more. * '''Portability''': VS is Windows-only. * '''Editor performance''': VS becomes less responsive on old machines. === Installing Visual Studio === # Download the ''installer'' for latest version of VS [https://visualstudio.microsoft.com/downloads/ here]. Run it. # From the installer, create a new install of VS. In workload selection menu, make sure you have ".NET desktop development" selected. In Individual components, search for ".NET Framework 4.8 targeting pack" and enable it too. # Start the installation, wait for it to finish. [[File:CodeEnv-VSInstaller.png|none|thumb|alt=Visual Studio installer screen|Visual Studio installer screen]] === Creating a project === When creating a project for a rain world mod, you will need to a '''class library''' targeting '''.NET Framework 4.8'''. There are some problems you may encounter on this step. * Occasionally Visual Studio refuses to display targeting Framework 4.8 as an option. The pattern is unclear. * Creating a project targeting fw4.8 from Visual Studio's GUI causes it to be made with old <code>.csproj</code> file format (msbuild 2003), which restricts some features and is generally more messy. '''Steps to tell if the project is in older format''': ** Open the file in a text editor ** If it looks like a pile of piss-soaked spaghetti and has <code>Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"</code> around the beginning, it's old. Thus it's recommended to create project files from the command line with <code>dotnet new</code>: [[File:CodeEnv-DotnetCLI.png|none|thumb|alt=Creating a project with dotnet CLI|Creating a project with dotnet CLI]] Then open the resulting .csproj in Visual Studio, double click the project name in solution structure, and change the first block to have tags with following values: === Adding references === To compile mods and access the game code, you need to add some assemblies to your project as ''references''. To do this, you can * Use <code>Project -> Add project reference...</code> in VS. * Manually add <code>Include</code>s to your .csproj. List of common required references is in the section [[#Common references]]. If you are planning to share your code at some point, it is recommended that you set up your references without using absolute paths on your PC. This can be done in few ways: * Copying the reference files to a folder inside or near the project folder. * Setting up a folder symlink from somewhere in the project to a reference dir. On Windows, you can use [https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink mklink /J] from command prompt. In either case, you should [https://git-scm.com/docs/gitignore gitignore] references if they happen to be in a repo to avoid redistributing others' code. === Building === After you've wrote something, you will naturally want to run it and see if it works. As of now, there is no way of attaching a debugger to Rain World process, and version of Mono packed with the game does not load .pdb files. Thus you should always build your mods on Release configuration, even if you're mid-development. To load a mod into the game, you need to copy its assembly into respective BepInEx active folder (<code>BepInEx/plugins/</code> unless you are making an [[MonoMod Patches|mmpatch]]). You can automate this step by using a build event: * In Project properties view in VS, find Build Events, and into Post-build insert one of these: ** Unconditional build event with hardcoded destination: <code>copy /Y "$(TargetPath)" "Path/to/your/plugins/folder/here"</code> ** Copies files into a path defined by environment variable <code>RWMods</code> (if it exists): <code>if defined RWMods (copy /Y "$(TargetPath)" "%RWMods%")</code> By default, building a project copies most of its dependencies to the build destination (<code>bin/release/</code>). You can prevent it by selecting desired references in solution explorer, opening properties dock and setting <code>Copy Local</code> to <code>No</code>: [[File:CodeEnv-copyLocal.png|thumb|none|alt=Disabling Copy Local|Disabling Copy Local]] |-| Simple code editor + dotnet CLI= {{todo|target=tab}} Another option is using a simpler code editor (such as [https://code.visualstudio.com/ Visual Studio Code] with a c# extension, or even [https://notepad-plus-plus.org/downloads/ notepad++] if you enjoy torture). This setup lacks advanced functions of Visual Studio, but allows you to write and build on non-windows systems. === Installing .NET SDK === Download the latest .NET SDK ([https://dotnet.microsoft.com/en-us/download/dotnet/6.0 6.0.400]) and install it. New SDKs are able to build projects for old runtimes. Use the SDK via <code>dotnet</code> from the command line. Full docs for the command can be found [https://docs.microsoft.com/en-us/dotnet/core/tools/ here]. === Creating a project === Use <code>dotnet new classlib -n [projectName]</code> to create a project. After it's there, open the .csproj file and edit the first <code>PropertyGroup</code> according to [[#csproj PropertyGroup]] section. After this is done, you can start writing. Any '''.cs''' file put into the project folder or one of its subfolders is automatically included. === Adding references === You can add a reference to the project by including <pre><nowiki> <Reference Include="path/to/Assembly.dll"> </Reference> </nowiki></pre> in an <code>ItemGroup</code>. Wildcards and relative paths are supported. To disable copying of references to target directory, change the include tag to look like the following: <pre><nowiki> <Reference Include="libs/*.dll"> <Private>false</Private> </Reference> </nowiki></pre> === Building === Use <code>dotnet build</code> in your project directory to build your project. Output goes into <code>bin/[Debug//Release]/</code> depending on your current configuration. </tabber> </div> ==== Common references ==== For all mods, it is a good idea to reference: {|class="wikitable" |- ! Assembly !! Contains |- | BepInEx/utils/PUBLIC-Assembly-CSharp.dll || All of the vanilla game code with access modifiers changed to stop any issues when modding |- | RainWorld_Data/Managed/UnityEngine.dll || Unity API methods |- | RainWorld_Data/Managed/UnityEngine.CoreModule.dll || Core Unity methods |- | RainWorld_Data/Managed/UnityEngine.InputLegacyModule.dll || Input handling used by the game |- | BepInEx/core/BepInEx.dll || [[BepInEx]] api |- | BepInEx/plugins/HOOKS-Assembly-CSharp.dll || Hookgen events for methods in Assembly-CSharp for easily attaching code |- | BepInEx/core/MonoMod.RuntimeDetour || Classes and methods necessary for applying manual detours/hooks |- | BepInEx/core/MonoMod.Utils.dll || Classes and methods necessary for applying IL hooks, as well as some additional functionality |} Additionally, if you want to use a dependency mod, you will likely need to reference it too. ==== csproj PropertyGroup ==== When creating a csproj file from CLI, you will need to edit it to have following values: {| class="wikitable" |- ! Tag !! Value !! Comment |- | TargetFramework || net48 || Framework version |- | ImplicitUsings || disable || Can not be used on .NET Framework 4.8 only 6+ |- | Nullable || disable || Toggles some compile-time null checking rules.<br />You can keep it enabled,<br />but it won't apply to the game code. |- | LangVersion || latest || Without this tag, language version stays at C#7.3<br />Later language versions include some handy features. |} ==== csproj structure ==== {{todo}} [[File:CodeEnv-csprojStructure.png|thumb|none|alt=Visual example|Visual example]] Official reference for .NET SDK .csproj format can be found [https://docs.microsoft.com/en-us/dotnet/core/project-sdk/msbuild-props here]. === Testing and Debugging === {{todo}} As mentioned, attaching a debugger to the game is currently not an option. This sections will contain several tips on mitigating the pain. * You can enable a separate console window for BepInEx output in <code>BepInEx/config/bepinex.cfg</code>. * From a [[BepInPlugins|BepInEx plugin]], use <code>Logger</code> property. If you need to use your logger in another class, include the following in your plugin class: <syntaxhighlight lang="csharp"> public static new ManualLogSource Logger { get; private set; } public void OnEnable() { Logger = base.Logger; } </syntaxhighlight> * [https://github.com/casheww/RW-ToolBox/releases/latest This plugin] by casheww might help you with specific tasks == Misc tips and trivia == {{todo}} * You can use Embedded Resources to include arbitrary data, such as text files or images, with your assembly. To do this, select a file in Solution explorer, open Properties dock, and set <code>Build action</code> to <code>Embedded Resource</code>. You can retrieve the resources as <code>byte[]</code>s using methods '''GetManifestResourceNames''' and '''GetManifestResourceStream''' on <code>System.Reflection.Assembly</code> instance. [[Category:Code Mods]] aa23cf6a0e4a33f7a2c79530b8340d8ab8f4d2cf BepInPlugins 0 95 365 360 2023-01-27T21:50:28Z Alextabitha 44 Changed reference to use BepInEx utils assembly file which removes any accessibility issues wikitext text/x-wiki BepInPlugins are a kind of game mod native to [[BepInEx]]. They are not compatible with Partiality. They should be placed in <code>Rain World/BepInEx/plugins</code>. == Creating a BepInPlugin == === Prerequisites === * A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary) * Rain World with RW BepInEx set up - see [[BepInEx|here]]. * Some kind of .NET programming environment, probably Visual Studio if you're on Windows, or Visual Studio Code for Linux/Mac. The guide below will assume you're already comfortable with the first prerequisite and your editor and environment of choice. ** The .NET Development pack for Visual Studio (or similar for other environments - you need to be able to use .NET Framework 4.8) === Step 1 - The project === Create a new C# .NET Framework 4.8 Class Library project in your IDE. You will then need to [https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019 add some references]. It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/core/BepInEx.dll</code> * <code>BepInEx/plugins/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/utils/PUBLIC-Assembly-CSharp.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.CoreModule.dll</code> === Step 2 - The BepInPlugin class === In a your new C# file, make a public class that has the <code>BepInEx.BepInPlugin</code> attribute and inherits from <code>BepInEx.BaseUnityPlugin</code> . The <code>BaseUnityPlugin</code> class inherits from <code>MonoBehaviour</code>, so you can use standard Unity script methods such as <code>OnEnable</code> and <code>OnDisable</code> in this class. The GUID should be unique to this plugin: something like "scholar" could be popular, which may result in BepInEx not loading your mod. Usually, people opt for the <code>username.mode_name</code> format. Include an assembly-level <code>SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)</code> declaration alongside your plugin class. This prevents errors later down the line. <syntaxhighlight lang="csharp"> using BepInEx; using System.Security.Permissions; [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] namespace SomeMod {     [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] // (GUID, mod name, mod version)     public class MyModName : BaseUnityPlugin     {     } } </syntaxhighlight> === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example:<syntaxhighlight lang="csharp"> [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] public class MyMod : BaseUnityPlugin {     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         /* This method will be subscribed to Player.Update. */         orig(self, eu);         /* Calling orig is what allows the original method and          * other hooks to the same method do their thing.          * Not calling this is almost always undesirable, and          * can cause big issues.          *   You can execute code before or after the call of          * orig as necessary.          */     } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote>Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and copy the mod's DLL file from wherever your build output is to <code>Rain World/BepInEx/plugins/</code> and run Rain World. == Enums == Due to their abundance in Rain World's code and their general usefulness in state machines, it's very possible that at some point you'll want to add your own value to an enum. To do that, you can use [[EnumExtender]]. == Advanced Techniques == === IL Hooking === IL hooking can be used to modify the Intermediate Language (IL) instructions of the game at runtime. This allows advanced editing of individual instructions within the game code. Risk of Thunder's guide to IL hooking can be found [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ here]. === RuntimeDetour === RuntimeDetour can be used to hook methods not covered by HOOKS-Assembly-CSharp.dll, as well as property getters and setters. A brief guide can be found on the [[MonoMod RuntimeDetour]] page. MonoMod's RuntimeDetour guide can be found [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md here]. === Harmony Patching === Harmony patching is a form of runtime patching. The HarmonyX wiki can be found [https://github.com/BepInEx/HarmonyX/wiki here]. [[Category:Code Mods]] 48f8786be5f5ecc9e183d4910a8867a6af24a3aa 369 365 2023-01-29T17:26:52Z Cashewww 2 /* Step 3 - Hooking */ wikitext text/x-wiki BepInPlugins are a kind of game mod native to [[BepInEx]]. They are not compatible with Partiality. They should be placed in <code>Rain World/BepInEx/plugins</code>. == Creating a BepInPlugin == === Prerequisites === * A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary) * Rain World with RW BepInEx set up - see [[BepInEx|here]]. * Some kind of .NET programming environment, probably Visual Studio if you're on Windows, or Visual Studio Code for Linux/Mac. The guide below will assume you're already comfortable with the first prerequisite and your editor and environment of choice. ** The .NET Development pack for Visual Studio (or similar for other environments - you need to be able to use .NET Framework 4.8) === Step 1 - The project === Create a new C# .NET Framework 4.8 Class Library project in your IDE. You will then need to [https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019 add some references]. It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/core/BepInEx.dll</code> * <code>BepInEx/plugins/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/utils/PUBLIC-Assembly-CSharp.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.CoreModule.dll</code> === Step 2 - The BepInPlugin class === In a your new C# file, make a public class that has the <code>BepInEx.BepInPlugin</code> attribute and inherits from <code>BepInEx.BaseUnityPlugin</code> . The <code>BaseUnityPlugin</code> class inherits from <code>MonoBehaviour</code>, so you can use standard Unity script methods such as <code>OnEnable</code> and <code>OnDisable</code> in this class. The GUID should be unique to this plugin: something like "scholar" could be popular, which may result in BepInEx not loading your mod. Usually, people opt for the <code>username.mode_name</code> format. Include an assembly-level <code>SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)</code> declaration alongside your plugin class. This prevents errors later down the line. <syntaxhighlight lang="csharp"> using BepInEx; using System.Security.Permissions; [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] namespace SomeMod {     [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] // (GUID, mod name, mod version)     public class MyModName : BaseUnityPlugin     {     } } </syntaxhighlight> === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example:<syntaxhighlight lang="csharp"> namespace SomeMod; [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] public class MyMod : BaseUnityPlugin {     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         /* This method will be subscribed to Player.Update. */         orig(self, eu);         /* Calling orig is what allows the original method and          * other hooks to the same method do their thing.          * Not calling this is almost always undesirable, and          * can cause big issues.          *   You can execute code before or after the call of          * orig as necessary.          */     } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote>Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and copy the mod's DLL file from wherever your build output is to <code>Rain World/BepInEx/plugins/</code> and run Rain World. == Enums == Due to their abundance in Rain World's code and their general usefulness in state machines, it's very possible that at some point you'll want to add your own value to an enum. To do that, you can use [[EnumExtender]]. == Advanced Techniques == === IL Hooking === IL hooking can be used to modify the Intermediate Language (IL) instructions of the game at runtime. This allows advanced editing of individual instructions within the game code. Risk of Thunder's guide to IL hooking can be found [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ here]. === RuntimeDetour === RuntimeDetour can be used to hook methods not covered by HOOKS-Assembly-CSharp.dll, as well as property getters and setters. A brief guide can be found on the [[MonoMod RuntimeDetour]] page. MonoMod's RuntimeDetour guide can be found [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md here]. === Harmony Patching === Harmony patching is a form of runtime patching. The HarmonyX wiki can be found [https://github.com/BepInEx/HarmonyX/wiki here]. [[Category:Code Mods]] bc1aa397f5e61174a05450bb8364ba882ea68fe3 384 369 2023-03-23T23:51:13Z Cashewww 2 removed reference to the BepInEx/plugins folder wikitext text/x-wiki BepInPlugins are the predominant form for Rain World code mods. They are a form of game mod native to [[BepInEx]]. They are not compatible with [[Partiality]]. == Creating a BepInPlugin == === Prerequisites === * A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary) * Rain World with RW BepInEx set up - see [[BepInEx|here]]. * Some kind of .NET programming environment, probably Visual Studio if you're on Windows, or Visual Studio Code for Linux/Mac. The guide below will assume you're already comfortable with the first prerequisite and your editor and environment of choice. ** The .NET Development pack for Visual Studio (or similar for other environments - you need to be able to use .NET Framework 4.8) === Step 1 - The project === Create a new C# .NET Framework 4.8 Class Library project in your IDE. You will then need to [https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019 add some references]. It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/core/BepInEx.dll</code> * <code>BepInEx/plugins/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/utils/PUBLIC-Assembly-CSharp.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.CoreModule.dll</code> === Step 2 - The BepInPlugin class === In a your new C# file, make a public class that has the <code>BepInEx.BepInPlugin</code> attribute and inherits from <code>BepInEx.BaseUnityPlugin</code> . The <code>BaseUnityPlugin</code> class inherits from <code>MonoBehaviour</code>, so you can use standard Unity script methods such as <code>OnEnable</code> and <code>OnDisable</code> in this class. The GUID should be unique to this plugin: something like "scholar" could be popular, which may result in BepInEx not loading your mod. Usually, people opt for the <code>username.mode_name</code> format. Include an assembly-level <code>SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)</code> declaration alongside your plugin class. This prevents errors later down the line. <syntaxhighlight lang="csharp"> using BepInEx; using System.Security.Permissions; [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] namespace SomeMod {     [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] // (GUID, mod name, mod version)     public class MyModName : BaseUnityPlugin     {     } } </syntaxhighlight> === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example:<syntaxhighlight lang="csharp"> namespace SomeMod; [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] public class MyMod : BaseUnityPlugin {     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         /* This method will be subscribed to Player.Update. */         orig(self, eu);         /* Calling orig is what allows the original method and          * other hooks to the same method do their thing.          * Not calling this is almost always undesirable, and          * can cause big issues.          *   You can execute code before or after the call of          * orig as necessary.          */     } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote>Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and copy the mod's DLL file from wherever your build output is to <code>Rain World/BepInEx/plugins/</code> and run Rain World. == Enums == Due to their abundance in Rain World's code and their general usefulness in state machines, it's very possible that at some point you'll want to add your own value to an enum. To do that, you can use [[EnumExtender]]. == Advanced Techniques == === IL Hooking === IL hooking can be used to modify the Intermediate Language (IL) instructions of the game at runtime. This allows advanced editing of individual instructions within the game code. Risk of Thunder's guide to IL hooking can be found [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ here]. === RuntimeDetour === RuntimeDetour can be used to hook methods not covered by HOOKS-Assembly-CSharp.dll, as well as property getters and setters. A brief guide can be found on the [[MonoMod RuntimeDetour]] page. MonoMod's RuntimeDetour guide can be found [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md here]. === Harmony Patching === Harmony patching is a form of runtime patching. The HarmonyX wiki can be found [https://github.com/BepInEx/HarmonyX/wiki here]. [[Category:Code Mods]] e5b78fc3cc7abb2fd1a0f0549616f2f0e1ef787d 389 384 2023-03-27T21:34:03Z Cashewww 2 /* Testing your code */ wikitext text/x-wiki BepInPlugins are the predominant form for Rain World code mods. They are a form of game mod native to [[BepInEx]]. They are not compatible with [[Partiality]]. == Creating a BepInPlugin == === Prerequisites === * A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary) * Rain World with RW BepInEx set up - see [[BepInEx|here]]. * Some kind of .NET programming environment, probably Visual Studio if you're on Windows, or Visual Studio Code for Linux/Mac. The guide below will assume you're already comfortable with the first prerequisite and your editor and environment of choice. ** The .NET Development pack for Visual Studio (or similar for other environments - you need to be able to use .NET Framework 4.8) === Step 1 - The project === Create a new C# .NET Framework 4.8 Class Library project in your IDE. You will then need to [https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019 add some references]. It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/core/BepInEx.dll</code> * <code>BepInEx/plugins/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/utils/PUBLIC-Assembly-CSharp.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.CoreModule.dll</code> === Step 2 - The BepInPlugin class === In a your new C# file, make a public class that has the <code>BepInEx.BepInPlugin</code> attribute and inherits from <code>BepInEx.BaseUnityPlugin</code> . The <code>BaseUnityPlugin</code> class inherits from <code>MonoBehaviour</code>, so you can use standard Unity script methods such as <code>OnEnable</code> and <code>OnDisable</code> in this class. The GUID should be unique to this plugin: something like "scholar" could be popular, which may result in BepInEx not loading your mod. Usually, people opt for the <code>username.mode_name</code> format. Include an assembly-level <code>SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)</code> declaration alongside your plugin class. This prevents errors later down the line. <syntaxhighlight lang="csharp"> using BepInEx; using System.Security.Permissions; [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] namespace SomeMod {     [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] // (GUID, mod name, mod version)     public class MyModName : BaseUnityPlugin     {     } } </syntaxhighlight> === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example:<syntaxhighlight lang="csharp"> namespace SomeMod; [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] public class MyMod : BaseUnityPlugin {     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         /* This method will be subscribed to Player.Update. */         orig(self, eu);         /* Calling orig is what allows the original method and          * other hooks to the same method do their thing.          * Not calling this is almost always undesirable, and          * can cause big issues.          *   You can execute code before or after the call of          * orig as necessary.          */     } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote>Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and find the Dynamic Link Library (DLL) file that it has compiled to. You then need to: # Create a folder and JSON for your mod, as described by [[Downpour Reference/Mod Directories]], and # Copy your mod DLL to a <code>plugins</code> folder within your mod's folder, as described by [[Downpour Reference/BepInEx Files]]. # Run the game and enable your mod by clicking on its name in the mod list in the Remix menu. Click the Apply Mods button. #* At time of writing, Rain World Remix does not support hot reloading of code mods, so the game needs to be restarted to apply your mod. == Enums == Due to their abundance in Rain World's code and their general usefulness in state machines, it's very possible that at some point you'll want to add your own value to an enum. To do that, you can use [[EnumExtender]]. == Advanced Techniques == === IL Hooking === IL hooking can be used to modify the Intermediate Language (IL) instructions of the game at runtime. This allows advanced editing of individual instructions within the game code. Risk of Thunder's guide to IL hooking can be found [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ here]. === RuntimeDetour === RuntimeDetour can be used to hook methods not covered by HOOKS-Assembly-CSharp.dll, as well as property getters and setters. A brief guide can be found on the [[MonoMod RuntimeDetour]] page. MonoMod's RuntimeDetour guide can be found [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md here]. === Harmony Patching === Harmony patching is a form of runtime patching. The HarmonyX wiki can be found [https://github.com/BepInEx/HarmonyX/wiki here]. [[Category:Code Mods]] 469a5f6426d3e06f9c42ab8bba51918280333b8a 390 389 2023-03-27T21:37:11Z Cashewww 2 /* Enums */ wikitext text/x-wiki BepInPlugins are the predominant form for Rain World code mods. They are a form of game mod native to [[BepInEx]]. They are not compatible with [[Partiality]]. == Creating a BepInPlugin == === Prerequisites === * A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary) * Rain World with RW BepInEx set up - see [[BepInEx|here]]. * Some kind of .NET programming environment, probably Visual Studio if you're on Windows, or Visual Studio Code for Linux/Mac. The guide below will assume you're already comfortable with the first prerequisite and your editor and environment of choice. ** The .NET Development pack for Visual Studio (or similar for other environments - you need to be able to use .NET Framework 4.8) === Step 1 - The project === Create a new C# .NET Framework 4.8 Class Library project in your IDE. You will then need to [https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019 add some references]. It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/core/BepInEx.dll</code> * <code>BepInEx/plugins/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/utils/PUBLIC-Assembly-CSharp.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.CoreModule.dll</code> === Step 2 - The BepInPlugin class === In a your new C# file, make a public class that has the <code>BepInEx.BepInPlugin</code> attribute and inherits from <code>BepInEx.BaseUnityPlugin</code> . The <code>BaseUnityPlugin</code> class inherits from <code>MonoBehaviour</code>, so you can use standard Unity script methods such as <code>OnEnable</code> and <code>OnDisable</code> in this class. The GUID should be unique to this plugin: something like "scholar" could be popular, which may result in BepInEx not loading your mod. Usually, people opt for the <code>username.mode_name</code> format. Include an assembly-level <code>SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)</code> declaration alongside your plugin class. This prevents errors later down the line. <syntaxhighlight lang="csharp"> using BepInEx; using System.Security.Permissions; [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] namespace SomeMod {     [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] // (GUID, mod name, mod version)     public class MyModName : BaseUnityPlugin     {     } } </syntaxhighlight> === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example:<syntaxhighlight lang="csharp"> namespace SomeMod; [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] public class MyMod : BaseUnityPlugin {     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         /* This method will be subscribed to Player.Update. */         orig(self, eu);         /* Calling orig is what allows the original method and          * other hooks to the same method do their thing.          * Not calling this is almost always undesirable, and          * can cause big issues.          *   You can execute code before or after the call of          * orig as necessary.          */     } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote>Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and find the Dynamic Link Library (DLL) file that it has compiled to. You then need to: # Create a folder and JSON for your mod, as described by [[Downpour Reference/Mod Directories]], and # Copy your mod DLL to a <code>plugins</code> folder within your mod's folder, as described by [[Downpour Reference/BepInEx Files]]. # Run the game and enable your mod by clicking on its name in the mod list in the Remix menu. Click the Apply Mods button. #* At time of writing, Rain World Remix does not support hot reloading of code mods, so the game needs to be restarted to apply your mod. == Enums == Due to their abundance in Rain World's code and their general usefulness in state machines, it's very possible that at some point you'll want to add your own value to an enum. To do that, you can use [[Downpour Reference/ExtEnum]]. == Advanced Techniques == === IL Hooking === IL hooking can be used to modify the Intermediate Language (IL) instructions of the game at runtime. This allows advanced editing of individual instructions within the game code. Risk of Thunder's guide to IL hooking can be found [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ here]. === RuntimeDetour === RuntimeDetour can be used to hook methods not covered by HOOKS-Assembly-CSharp.dll, as well as property getters and setters. A brief guide can be found on the [[MonoMod RuntimeDetour]] page. MonoMod's RuntimeDetour guide can be found [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md here]. === Harmony Patching === Harmony patching is a form of runtime patching. The HarmonyX wiki can be found [https://github.com/BepInEx/HarmonyX/wiki here]. [[Category:Code Mods]] 1f07f94db41806b28241796f4e95e7ebe2ad3507 Downpour Reference/Mod Directories 0 145 367 359 2023-01-28T14:15:02Z SabreML 46 Added a v to the `target_game_version` example (since it's needed), and a note explaining where to easily find the current game version. wikitext text/x-wiki Each mod in Downpour is stored as a subfolder inside the &quot;RainWorld_Data/StreamingAssets/mods&quot; directory. This subfolder contains all metadata, file modifications and overrides, assets, and code modules (DLL files) that define the mod's contents and functionality. == ModInfo JSON == Each mod should have a &quot;modinfo.json&quot; file included in the top level directory of the mod. This JSON file defines the metadata for the mod, mainly the information that will be displayed for that mod within the REMIX menu. The following key-value pairs exist for this JSON file: {|class="wikitable" ! Key !! Meaning |- | id || This is a unique string identifier for this mod. This identifier should never be changed. Recommended to be a lower-case string with no spaces. Other mods will reference this ID to refer to your mod, such as when listing mod requirements. |- | name || This is the title of your mod that will be shown and listed in the REMIX menu. |- | version || This is a string specifying the current version number of your mod. |- | target_game_version || The version number of Rain World this mod was made for. (''The current game version can be found in "RainWorld_Data/StreamingAssets/GameVersion.txt"'') |- | authors || A string listing the authors of the mod. The &lt;LINE&gt; keyword can be used to add a breakline. If the authors string is too long to be displayed directly, it will be converted to a credits roll in the REMIX menu. |- | description || A longer description of the functionality of the mod, to be displayed in the REMIX menu. The &lt;LINE&gt; keyword can be used to add a breakline. |- | youtube_trailer_id || Optionally, specify the ID for a YouTube video to associate with this mod as a preview trailer. The ID is the text after ?v= in a YouTube video URL. |- | requirements || An array of strings specifying other mods which must be installed to use this mod. Each string in the array should match the '''id''' key of the required mod. |- | requirements_names || A parallel array to the '''requirements''' array, which you can use to display more user friendly names for the requirements in the REMIX menu rather than displaying their internal '''id''' string. |- | checksum_override_version || An optional boolean parameter. If false, or omitted, the mod will be considered &quot;updated&quot; if changes are found to any files in the mod's folder. If true, the mod will only be considered &quot;updated&quot; if the value of the '''version''' parameter changes. (''See additional notes in the next section below'') |} An example modinfo.json file contents: <syntaxhighlight lang="json"> { "id": "testmod", "name": "Test Mod", "version": "1.0", "target_game_version": "v1.5", "authors": "AndrewFM", "description": "This mod does something interesting, probably!", "youtube_trailer_id": "u-cuf39rK8g", "requirements": ["bestmod", "vrmod"], "requirements_names": ["That Other Mod", "Virtual Reality Support"], "checksum_override_version": false } </syntaxhighlight> In addition to the modinfo.json file, the mod directory can also include a '''thumbnail.png''' image to be displayed in the REMIX menu. This should be an image with 16:9 aspect ratio, recommended to be at least 640x360 pixels large. Additionally, the file size of this thumbnail image should remain below 1 MB. === Checksum Override === Note that the "'''checksum_override_version'''" flag can also be useful during development of your mod when file changes will be frequent. This will suppress the checksum validation and prevent the normal workflow of resolving file changes, merges, and mod conflicts, which can save you time when relaunching the game and/or enabling your mod. However, it is recommended to turn this flag back off before distributing your mod. If you leave it enabled and forget to update your mod's version before distributing the update, it may break your mod for people who already had it installed and enabled, as it will suppress the default update resolution workflow. == Overwriting Files == The contents of the mod folder are a mirror of the StreamingAssets folder. For example, if you wanted your mod to replace the image file at: <pre>      "Assets/StreamingAssets/futile/resources/illustrations/maintitle.png" </pre> with a different image, you would place the new image at: <pre>      "your-mod-folder/futile/resources/illustrations/maintitle.png" </pre> Since the directory structure and file name match one of the original game's files, the game will use the version from your mod directory instead of the original version of the file, whenever your mod is enabled. In some cases files outside the StreamingAssets folder can be modified as well. For example to modify sound effects (Assets/LoadedSoundEffects) your folder structure would be: <pre>      "your-mod-folder/futile/resources/loadedsoundeffects/..." </pre> Or to modify music files (Assets/Music), the structure would be: <pre>      "your-mod-folder/futile/resources/music/..." </pre> Refer to [[Downpour Reference/Modification Files]] for other ways to modify existing files other than completely overwriting their contents, for better mod compatibility. == AssetManager == Whenever referencing any asset files from disk in your code (whether they be files from within your mod's folder, or files within the base game's folders), you should use the static utility functions offered by the AssetManager class. This ensures the file path to the correct version of the file is used based on which mods are enabled or disabled, following the logic above. For example: <pre>AssetManager.ResolveFilePath(&quot;futile/resources/illustrations/maintitle.png&quot;);</pre> This would return the file path to the vanilla maintitle.png file. However, if the example mod described in the previous section were enabled, this instead would return the file path to that mod's overwritten version of maintitle.png. The available utility functions are: {|class="wikitable" ! Method !! Meaning |- | '''ResolveFilePath(path)''' || Return the correct path to the given file based on enabled/disabled mods. |- | '''ResolveDirectory(path)''' || Return the correct path to the given subdirectory based on enabled/disabled mods. |- | '''ListDirectory(path)''' || Returns all unique files contained in all versions of the given subdirectory based on enabled/disabled mods. |- | '''ListDirectory(path, true)''' || Returns all unique subdirectories contained in all versions of the given subdirectory based on enabled/disabled mods. |} To give an example of ListDirectory, consider a hypothetical vanilla directory at: <pre>      "Assets/StreamingAssets/futile/resources/example" </pre> which contained the files "a.txt", "b.txt", and "c.txt". Then say you created a mod which included the folder: <pre>      "your-mod-folder/futile/resources/example" </pre> which contained the files "c.txt", and "d.txt". Then when the code below is executed: <pre> AssetManager.ListDirectory("futile/resources/example"); </pre> If your mod is disabled, the files "a.txt" (vanilla), "b.txt" (vanilla), "c.txt" (vanilla) would be returned. If your mod is enabled, the files "a.txt" (vanilla), "b.txt" (vanilla), "c.txt" (modded), "d.txt" (modded) would be returned. a09f8d6f7315acb347383297bd89f7d4ed2dbc01 377 367 2023-02-23T15:09:22Z SabreML 46 Adds an entry for the new workshop tags wikitext text/x-wiki Each mod in Downpour is stored as a subfolder inside the &quot;RainWorld_Data/StreamingAssets/mods&quot; directory. This subfolder contains all metadata, file modifications and overrides, assets, and code modules (DLL files) that define the mod's contents and functionality. == ModInfo JSON == Each mod should have a &quot;modinfo.json&quot; file included in the top level directory of the mod. This JSON file defines the metadata for the mod, mainly the information that will be displayed for that mod within the REMIX menu. The following key-value pairs exist for this JSON file: {|class="wikitable" ! Key !! Meaning |- | id || This is a unique string identifier for this mod. This identifier should never be changed. Recommended to be a lower-case string with no spaces. Other mods will reference this ID to refer to your mod, such as when listing mod requirements. |- | name || This is the title of your mod that will be shown and listed in the REMIX menu. |- | version || This is a string specifying the current version number of your mod. |- | target_game_version || The version number of Rain World this mod was made for. (''The current game version can be found in "RainWorld_Data/StreamingAssets/GameVersion.txt"'') |- | authors || A string listing the authors of the mod. The &lt;LINE&gt; keyword can be used to add a breakline. If the authors string is too long to be displayed directly, it will be converted to a credits roll in the REMIX menu. |- | description || A longer description of the functionality of the mod, to be displayed in the REMIX menu. The &lt;LINE&gt; keyword can be used to add a breakline. |- | youtube_trailer_id || Optionally, specify the ID for a YouTube video to associate with this mod as a preview trailer. The ID is the text after ?v= in a YouTube video URL. |- | requirements || An array of strings specifying other mods which must be installed to use this mod. Each string in the array should match the '''id''' key of the required mod. |- | requirements_names || A parallel array to the '''requirements''' array, which you can use to display more user friendly names for the requirements in the REMIX menu rather than displaying their internal '''id''' string. |- | tags || An array of strings specifying the Steam Workshop tags which will be added to this mod. These should match the tags listed on the game's workshop page. |- | checksum_override_version || An optional boolean parameter. If false, or omitted, the mod will be considered &quot;updated&quot; if changes are found to any files in the mod's folder. If true, the mod will only be considered &quot;updated&quot; if the value of the '''version''' parameter changes. (''See additional notes in the next section below'') |} An example modinfo.json file contents: <syntaxhighlight lang="json"> { "id": "testmod", "name": "Test Mod", "version": "1.0", "target_game_version": "v1.5", "authors": "AndrewFM", "description": "This mod does something interesting, probably!", "youtube_trailer_id": "u-cuf39rK8g", "requirements": ["bestmod", "vrmod"], "requirements_names": ["That Other Mod", "Virtual Reality Support"], "tags": ["Game Mechanics"], "checksum_override_version": false } </syntaxhighlight> In addition to the modinfo.json file, the mod directory can also include a '''thumbnail.png''' image to be displayed in the REMIX menu. This should be an image with 16:9 aspect ratio, recommended to be at least 640x360 pixels large. Additionally, the file size of this thumbnail image should remain below 1 MB. === Checksum Override === Note that the "'''checksum_override_version'''" flag can also be useful during development of your mod when file changes will be frequent. This will suppress the checksum validation and prevent the normal workflow of resolving file changes, merges, and mod conflicts, which can save you time when relaunching the game and/or enabling your mod. However, it is recommended to turn this flag back off before distributing your mod. If you leave it enabled and forget to update your mod's version before distributing the update, it may break your mod for people who already had it installed and enabled, as it will suppress the default update resolution workflow. == Overwriting Files == The contents of the mod folder are a mirror of the StreamingAssets folder. For example, if you wanted your mod to replace the image file at: <pre>      "Assets/StreamingAssets/futile/resources/illustrations/maintitle.png" </pre> with a different image, you would place the new image at: <pre>      "your-mod-folder/futile/resources/illustrations/maintitle.png" </pre> Since the directory structure and file name match one of the original game's files, the game will use the version from your mod directory instead of the original version of the file, whenever your mod is enabled. In some cases files outside the StreamingAssets folder can be modified as well. For example to modify sound effects (Assets/LoadedSoundEffects) your folder structure would be: <pre>      "your-mod-folder/futile/resources/loadedsoundeffects/..." </pre> Or to modify music files (Assets/Music), the structure would be: <pre>      "your-mod-folder/futile/resources/music/..." </pre> Refer to [[Downpour Reference/Modification Files]] for other ways to modify existing files other than completely overwriting their contents, for better mod compatibility. == AssetManager == Whenever referencing any asset files from disk in your code (whether they be files from within your mod's folder, or files within the base game's folders), you should use the static utility functions offered by the AssetManager class. This ensures the file path to the correct version of the file is used based on which mods are enabled or disabled, following the logic above. For example: <pre>AssetManager.ResolveFilePath(&quot;futile/resources/illustrations/maintitle.png&quot;);</pre> This would return the file path to the vanilla maintitle.png file. However, if the example mod described in the previous section were enabled, this instead would return the file path to that mod's overwritten version of maintitle.png. The available utility functions are: {|class="wikitable" ! Method !! Meaning |- | '''ResolveFilePath(path)''' || Return the correct path to the given file based on enabled/disabled mods. |- | '''ResolveDirectory(path)''' || Return the correct path to the given subdirectory based on enabled/disabled mods. |- | '''ListDirectory(path)''' || Returns all unique files contained in all versions of the given subdirectory based on enabled/disabled mods. |- | '''ListDirectory(path, true)''' || Returns all unique subdirectories contained in all versions of the given subdirectory based on enabled/disabled mods. |} To give an example of ListDirectory, consider a hypothetical vanilla directory at: <pre>      "Assets/StreamingAssets/futile/resources/example" </pre> which contained the files "a.txt", "b.txt", and "c.txt". Then say you created a mod which included the folder: <pre>      "your-mod-folder/futile/resources/example" </pre> which contained the files "c.txt", and "d.txt". Then when the code below is executed: <pre> AssetManager.ListDirectory("futile/resources/example"); </pre> If your mod is disabled, the files "a.txt" (vanilla), "b.txt" (vanilla), "c.txt" (vanilla) would be returned. If your mod is enabled, the files "a.txt" (vanilla), "b.txt" (vanilla), "c.txt" (modded), "d.txt" (modded) would be returned. e5b180437bd345d9a567c6d036b19ffbf4a22657 402 377 2023-03-29T00:41:45Z SabreML 46 Minor <code>ing. (And added a note about the 'v' in `target_game_version`) wikitext text/x-wiki Each mod in Downpour is stored as a subfolder inside the <code>RainWorld_Data/StreamingAssets/mods</code> directory. This subfolder contains all metadata, file modifications and overrides, assets, and code modules (DLL files) that define the mod's contents and functionality. == ModInfo JSON == Each mod should have a <code>modinfo.json</code> file included in the top level directory of the mod. This JSON file defines the metadata for the mod, mainly the information that will be displayed for that mod within the REMIX menu. The following key-value pairs exist for this JSON file: {|class="wikitable" ! Key !! Meaning |- | id || This is a unique string identifier for this mod. This identifier should never be changed. Recommended to be a lower-case string with no spaces. Other mods will reference this ID to refer to your mod, such as when listing mod requirements. |- | name || This is the title of your mod that will be shown and listed in the REMIX menu. |- | version || This is a string specifying the current version number of your mod. |- | target_game_version || The version number of Rain World this mod was made for. Note that this must start with a "v". (''The current game version can be found in <code>RainWorld_Data/StreamingAssets/GameVersion.txt</code>'') |- | authors || A string listing the authors of the mod. The &lt;LINE&gt; keyword can be used to add a breakline. If the authors string is too long to be displayed directly, it will be converted to a credits roll in the REMIX menu. |- | description || A longer description of the functionality of the mod, to be displayed in the REMIX menu. The &lt;LINE&gt; keyword can be used to add a breakline. |- | youtube_trailer_id || Optionally, specify the ID for a YouTube video to associate with this mod as a preview trailer. The ID is the text after ?v= in a YouTube video URL. |- | requirements || An array of strings specifying other mods which must be installed to use this mod. Each string in the array should match the '''id''' key of the required mod. |- | requirements_names || A parallel array to the "'''requirements'''" array, which you can use to display more user friendly names for the requirements in the REMIX menu rather than displaying their internal '''id''' string. |- | tags || An array of strings specifying the Steam Workshop tags which will be added to this mod. These should match the tags listed on the game's workshop page. |- | checksum_override_version || An optional boolean parameter. If false, or omitted, the mod will be considered &quot;updated&quot; if changes are found to any files in the mod's folder. If true, the mod will only be considered &quot;updated&quot; if the value of the '''version''' parameter changes. (''See additional notes in the next section below'') |} An example modinfo.json file contents: <syntaxhighlight lang="json"> { "id": "testmod", "name": "Test Mod", "version": "1.0", "target_game_version": "v1.5", "authors": "AndrewFM", "description": "This mod does something interesting, probably!", "youtube_trailer_id": "u-cuf39rK8g", "requirements": ["bestmod", "vrmod"], "requirements_names": ["That Other Mod", "Virtual Reality Support"], "tags": ["Game Mechanics"], "checksum_override_version": false } </syntaxhighlight> In addition to the modinfo.json file, the mod directory can also include a '''thumbnail.png''' image to be displayed in the REMIX menu. This should be an image with 16:9 aspect ratio, recommended to be at least 640x360 pixels large. Additionally, the file size of this thumbnail image should remain below 1 MB. === Checksum Override === Note that the "'''checksum_override_version'''" flag can also be useful during development of your mod when file changes will be frequent. This will suppress the checksum validation and prevent the normal workflow of resolving file changes, merges, and mod conflicts, which can save you time when relaunching the game and/or enabling your mod. However, it is recommended to turn this flag back off before distributing your mod. If you leave it enabled and forget to update your mod's version before distributing the update, it may break your mod for people who already had it installed and enabled, as it will suppress the default update resolution workflow. == Overwriting Files == The contents of the mod folder are a mirror of the StreamingAssets folder. For example, if you wanted your mod to replace the image file at: <pre>      "Assets/StreamingAssets/futile/resources/illustrations/maintitle.png" </pre> with a different image, you would place the new image at: <pre>      "your-mod-folder/futile/resources/illustrations/maintitle.png" </pre> Since the directory structure and file name match one of the original game's files, the game will use the version from your mod directory instead of the original version of the file, whenever your mod is enabled. In some cases files outside the StreamingAssets folder can be modified as well. For example to modify sound effects (Assets/LoadedSoundEffects) your folder structure would be: <pre>      "your-mod-folder/futile/resources/loadedsoundeffects/..." </pre> Or to modify music files (Assets/Music), the structure would be: <pre>      "your-mod-folder/futile/resources/music/..." </pre> Refer to [[Downpour Reference/Modification Files]] for other ways to modify existing files other than completely overwriting their contents, for better mod compatibility. == AssetManager == Whenever referencing any asset files from disk in your code (whether they be files from within your mod's folder, or files within the base game's folders), you should use the static utility functions offered by the <code>AssetManager</code> class. This ensures the file path to the correct version of the file is used based on which mods are enabled or disabled, following the logic above. For example: <pre>AssetManager.ResolveFilePath(&quot;futile/resources/illustrations/maintitle.png&quot;);</pre> This would return the file path to the vanilla maintitle.png file. However, if the example mod described in the previous section were enabled, this instead would return the file path to that mod's overwritten version of maintitle.png. The available utility functions are: {|class="wikitable" ! Method !! Meaning |- | '''ResolveFilePath(path)''' || Return the correct path to the given file based on enabled/disabled mods. |- | '''ResolveDirectory(path)''' || Return the correct path to the given subdirectory based on enabled/disabled mods. |- | '''ListDirectory(path)''' || Returns all unique files contained in all versions of the given subdirectory based on enabled/disabled mods. |- | '''ListDirectory(path, true)''' || Returns all unique subdirectories contained in all versions of the given subdirectory based on enabled/disabled mods. |} To give an example of ListDirectory, consider a hypothetical vanilla directory at: <pre>      "Assets/StreamingAssets/futile/resources/example" </pre> which contained the files "a.txt", "b.txt", and "c.txt". Then say you created a mod which included the folder: <pre>      "your-mod-folder/futile/resources/example" </pre> which contained the files "c.txt", and "d.txt". Then when the code below is executed: <pre> AssetManager.ListDirectory("futile/resources/example"); </pre> If your mod is disabled, the files "a.txt" (vanilla), "b.txt" (vanilla), "c.txt" (vanilla) would be returned. If your mod is enabled, the files "a.txt" (vanilla), "b.txt" (vanilla), "c.txt" (modded), "d.txt" (modded) would be returned. be74ae7dccf0c2c5e1057ca5668fa11df8c56672 Downpour Reference/BepInEx Files 0 148 368 285 2023-01-29T16:52:59Z Cashewww 2 /* Utility Files */ wikitext text/x-wiki DLL files are stored in and loaded directly from the mod folders. This page describes how BepInEx is handled in Downpour. == Directory Structure == === Toggleable DLLs === The DLL files for your mod will go within a cooresponding location in your mod's folder. DLL files included this way can be toggled on and off using the in-game REMIX menu. DLL files can be called any name, but need to be placed into the following folders to be recognized: * <code>your-mod-folder/plugins/*.dll</code> - Location for any BepInPlugins. * <code>your-mod-folder/patchers/*.dll</code> - Location for any patch mods. Note that Downpour does not attempt to hot-reload DLL mods. If a mod is toggled on or off in the REMIX menu that contains a DLL file, the game will force a relaunch to finish the mod applying process. == Mod Lifecycle Functions == The following lifecycle functions exist in the RainWorld class that can be useful for initializing/uninitializing, loading/unloading resources for your mod when it is toggled on and off. {|class="wikitable" ! style="width: 10%" | Method !! style="width: 90%" | Meaning |- | '''OnModsInit()''' || Called when the game is first launched if your mod is one of the enabled mods. Also called any time mods are applied in the REMIX menu if your mod is one of the enabled mods. Because it is called any time the apply button is pressed, expect that this function can be called multiple times in a single game session, so provide checks to ensure you are not double-loading resources if it is called again. |- | '''PreModsInit()''' || Called right before the OnModsInit() function. |- | '''PostModsInit()''' || Called right after the OnModsInit() function. |- | '''OnModsEnabled()''' || Unlike the init function, this is not called when the game is launched. It is called when mods are applied in the REMIX menu, if your mod is now enabled, but ''only'' if it was previously disabled. This is unlike the init function which will be called whenever your mod is enabled even if it was previously enabled as well. This function recieves an argument which contains a list of all newly enabled mods that weren't previously enabled. |- | '''OnModsDisabled()''' || The opposite of the above function. Called when mods are applied in the REMIX menu, if the mod is now disabled, but ''only'' if it was previously enabled. This function recieves an argument which contains a list of all newly disabled mods that were previously enabled. |- | '''PreModsDisabledEnabled()''' || Called before any of the enabled/disabled/init functions are called. Only part of the apply mods workflow; does not get called on game launch. |- | '''PostModsDisabledEnabled()''' || Called after all of the enabled/disabled/init functions are finished being called. Only part of the apply mods workflow; does not get called on game launch. |} == Utility Files == For convenience, the following Assembly-CSharp associated files are automatically generated and available for use: * <code>BepInEx/plugins/HOOKS-Assembly-CSharp.dll</code> - Hookgen for Assembly-CSharp * <code>BepInEx/utils/PUBLIC-Assembly-CSharp.dll</code> - Assembly-CSharp with all members public 6ee8e5ea0d921926e4f632db1853e3d5c0d848fd Level Editor 0 86 372 348 2023-02-10T07:29:58Z Zoda390 78 /* Quirks: Separated the quirks for an easier read*/ wikitext text/x-wiki {{Cleanup}} == The Official Level Editor == [[File:editorFront.png|400px|thumb|right]] The Rain World level editor is a powerful tool that allows the creation of new rooms for the game, and editing existing rooms. It is the same editor the developers used to make all of the rooms for the base game. It takes specially formatted spritesheets and a number of programmed effects and outputs png files that the engine interprets in 3D (as well as an accompanying text file which contains collision and gameplay info). You can download the level editor from [https://ln.sync.com/dl/db7b0cf70/nebg7d6b-qg7gjua7-gjdi94jn-xuvivhw3/view/default/8384962820004 here.] There is also the Community Editor, which is a community-made edit of the original editor, with new features, bugfixes, and better ease of use. There is also Drizzle, a community made level renderer that's hardware accelerated. In the future it intends to replace the existing level editors. === Basic Features Overview === Once you've followed the on-screen instructions for either creating or opening a level, you are presented with the dashboard/preview screen. From here, you can switch between the different editors, load or save your level, and export it for use in-game. The preview presented here requires being manually updated whenever changes are made or when you first open a level. Pressing "1" at any point will bring you back to this screen so you can save your level or switch to a different editor. It's often best to start by modifying the dimensions of the room to your liking using the level size button before beginning to edit. You can change this at any time, but because you set the dimensions manually rather than visually, making changes later is more difficult and poses the risk of accidentally deleting a portion of your room if you aren't careful. From the dashboard you can switch to the Geometry Editor (for defining the level geometry and collision), the Tile Editor (for customizing the tiles and assets that make up the geometry created in the geometry editor), the Effects Editor (for adding procedural effects like erosion or slime, as well as things like plants or chains), the Light Editor (for customizing the light and shadow in your room), or the Prop Editor (for adding additional hand placed props and decals like graffiti). === Controls Overview === ==== View controls (numpad): ==== These are used for every editor view except the Camera and Environment editor to scroll around the screen. Notice, numlock must be turned on for these controls to have any effect. {| class="wikitable" |+ |- ! Key(s) !! Function |- | 8,2,4,6 || Moves view |- | 1 (hold) || Increases view scroll speed. |- | 3 (hold) || Increases view scroll speed even more. |- | 9 (hold) || Allow the view to move outside the boundaries of the level. |} ==== Menu keybinds (Number row): ==== These act as hotkeys to quickly switch between different editor views. These can be used in any editor view as well. {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | 1 || Main menu |- | 2 || Geometry |- | 3 || Tiles |- | 4 || Cameras |- | 5 || Light |- | 6 || Room size |} === Level Settings === ==== Level Size ==== This is where you change how big the level is. You can set the entire level size, and border tiles. Border tiles are padding around the room, mainly for resolutions that are larger than 4:3 It's recomended not to go under the defaults, or your final render will be cut off. ==== Default Medium ==== This determines if you can fall outside of the level or not, death pits still work the same either way however. ==== Light Type ==== The light type can either be set to '''ON''' which will use what you have done in the Light Editor, or '''OFF''' which paints everything in shadow. ==== Seed ==== This is the arrow on the fourth row of bars, which determines what seed the level will use. The seed determines random tile and prop placement, along with how effects are generated. === Rendering === ==== Prioritize Cam ==== This determines what camera will be rendered first, before starting from the beginning. Very useful for re-rendering a specific screen. ==== Text Output ==== This outputs a .txt of the level's geometry, usable in-game. ==== Render Level ==== This renders the screens ==== Mass Render ==== This will render every level in the selected folder. === Editors === <tabber> |-|Geometry Editor= == Geometry Editor == [[File: geoEditor.png|400px|thumb|right]] The Geometry Editor is the first stop for the creation of new rooms. In the Geometry Editor, you define the gameplay and collision information of your room, such as the placement of vertical and horizontal bars, shortcuts, room entrances, creature dens, and garbage worm placement. (to connect your room to other rooms), and a number of other gameplay relevant elements. === Controls === {| class="wikitable" |+ Geometry editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | Arrow keys || Primary cursor scroll through toolbox. If mouse over the toolbox, mouse moves cursor instead. |- | Mouse || Primary cursor movement. |- | LMB || Primary cursor use current tool. |- | Q (hold) || Secondary cursor scroll through toolbox. |- | E,S,D,F || Secondary cursor movement. |- | W || Secondary cursor use current tool. |} As an experimental feature, the developers implemented a second cursor and control scheme to allow two users to edit a room simultaneously (with the second user entirely on the keyboard). While this ended up being a little used feature (as far as we are aware), it is still implemented in the current editor (represented by the grey cursor). == Toolbox == {| class="wikitable" |+ Level Editor Geo Tools |- | Inverse || Flips the currently selected tile between walls, and air. |- | Paint Walls || Paints solid tiles. |- | Paint Air || Paints non-solid tiles. |- | Make Slope || Paints a slope, these can only be placed inside corners, and as the edges of larger solids. |- | Make Floor || Paints thin platforms that you can stand on, but also hold down to fall through. |- | Rect Wall || Paints solid tiles in a rectangle. Click two points to set the rectangle's dimensions and paint. |- | Rect Air || Same as above, except for non-solid tiles. |- | Worm Grass || Placed above solid ground to spawn worm grass tendrils. The number placed together to the left and right decides the height of the grass. |- | Crack Terrain || Renders as a roughly cracked fissure through the material painted on it in the tile editor. Slugcat can crawl through these tunnels. An example in the vanilla game is in the western temple styled area of the subterranean. Where there are fissures to travel beneath certain stone statues. |- | Horizontal Beam || Climbable pole. Slugcat can only climb these on layer 1. |- | Vertical Beam || Same as above, except in the other direction. |- | Glass Wall || Paints invisible solid walls. |- | Waterfall || Will cause a waterfall to appear in game, with this tile at the top of it. |} {| class="wikitable" |+ Level Editor Item and Batfly Tools |- | Place Rock || A Rock will spawn at this location with a 60% chance. |- | Place Spear ||A Spear will spawn at this location with a 60% chance. |- | Spawn Fly || Does nothing. |- | Forbid Fly Chains || Prevents bat flies from hanging together in specific locations to rest. |- | Hive || Places a bat fly hive. Bat flies can use these to quickly travel to different parts of a room. |} === Short Cuts and Entrances === [[File: shortcuts_yes.png|270px|thumb|Examples of working shortcuts]] [[File: shortcuts_no.png|270px|right|thumb|Examples of broken shortcuts]] {| class="wikitable" |+ Level Editor Shortcut Tools |- | Short Cut Entrance || Places the entrance of a short cut into the room, these must be fully surrounded by ground except from the entrance side and the exit will always be aiming in the oposite direction of the entrance. When placed on the floor, both players and creatures will fall into them, so its advised to always put a platform in the entrance instead of air in these cases. |- | Short Cut || Places a short cut's travel dot. These can connect two short cut entrances together or connect into a specific entrance or den variation. They can also have no destination, in which case the shortcut entrance will simply be blocked. Short cut dots can cross with each other in a + pattern and each path will always continue forwards. |- | Dragon Den || Places a creature den. These hold the creature assigned to that den in the region's World File. Creatures can move to the closest den if they cant return to their own. |- | Entrance || Used to connect with another room. These can be used by Slugcat and most creatures to travel across a region, the 2 rooms connected by this entrance are determined in the region's World File. |- | Scavenger Hole || Allows scavengers to spawn or travel to this room as they wander through a region. Since scavenger use offscreen dens, all the Scavenger Holes will share the same pool of scavengers. |- | Whack-A-Mole-Hole || Allows creatures to travel arround a room by "teleporting" between these holes. There is no limit to how many holes can be placed in the same room and they are all connected with each other. When a creature enters one of these holes and selects a new destination there is a short period of time in which the shortcut segment glows, so they are often used without Short Cut dots. |- | "G" Garbage Worm den || Unlike the rest of dens, its not attached to a short cut entrance. Instead they are simply placed in the ground tile where we want the Garbage Worm to spawn. |} A short cut dot is not required between the short cut's entrance and the den or door it's connecting to. However, the shortcut must show as an arrow toward the den or door for the link to it to be proper. Short cuts and their connections to the various kinds of entrances in Rain World have specific needs! Improperly making the short cut can lead to crashes, or odd behavior in game. A list of common mistakes include: * Short cuts going outside of the level bounds, anything out of the white frame won't be loaded in game. * Short cut entrances placed directly on the surface. * Short cut entrances with short cut dots on any side which isn't the opposite to the entrance. * Creature dens or room entrances randomly floating in the room disconnected from everything. * Placing Garbage Worm dens connected to an entrance like the other dens. === Layer Info === {| class="wikitable" |+ Level Editor Layer and Misc Tools |- | Copy Backwards || Copies a rectangle of tiles on the current layer to the next layer. This does not wrap around back to layer 1 if you are on layer 3. |- | Work Layer || Changes layers from 1 to 3 and then back to 1. |- | Clear All || Selects a rectangle that resets all tiles inside it, on all layers, back to open air. |- | Toggle Mirror || Turns on and off a mirror tile painting mode. What you do on one side of the mirror will be copied on the other. |- | Move Mirror || Allows you to move the location of the Mirror. |- | Move Level || Moves the whole level in a certain direction. Place the mouse cursor outside the level, then use the arrow keys to move the level in the direction you want. It will not work if your mouse is inside the level as using the arrow keys will swap to another tool. |- | Empty || Does nothing. Good to set as your tool if you have to tab out, as it does nothing. |} Rain World levels consist of 3 layers, each representing a different depth. This layer info is represented visually through the color of tiles, and you can switch between editing on different layers with the work layer tool in the bottom left of the tool panel. Layer 1 draws in full black, layer 2 draws in green, and layer 3 draws in red. These colors will blend if multiple layers are drawn on top of each other. Layer 1 is the foreground, and any filled tiles on this layer will have collision. This is the base layer you define for the sake of gameplay, as any air here is space you can traverse. Layer 2 is the midground, which you can imagine as the back wall of your room. Wall climbing creatures also interact with this. Layer 3 is the extreme background, behind the back wall of the room (for placing distant objects or giving the room a section of open sky). Nothing interacts with this at all. Note: The tile editor defines the visual tiles and props that make up this geometry, so in order to place solid objects in the tile editor (on any layer), those tiles need to be filled here in the geometry editor. Even though the mid-ground and background do not provide any collision geometry, in order to place solid props on those layers the tiles need to be filled here in the geometry editor. Similarly, some props can only be placed on air on the layers (like fences). === Tips and Tricks === - Many of the gameplay features require that they be placed within the margins of your room (represented by the white border). An entrance or creature den placed outside of your margins will render your room un-enterable at best, and crash the game at worst. Short Cut Entrances and Short Cuts can be placed outside the level boundary just fine, however. - Border tiles are tiles that can't be interacted with, and are there for looks only. The room will copy the last tile from the border forever in that direction so be careful with your geometry, or you'll be able to walk out of bounds through "solid" walls or stand in the air. - Because the tool panel loops around from top to bottom and left to right, when editing the base geometry (walls and air) it's faster to use the arrow keys to go up to reach the work layer tool to swap layers than to cycle through the whole list to reach them. Also, the rectangular wall and air tools will let you edit large chunks of your level much faster than going tile by tile. - Because the layers move with a parallax effect, it's often necessary to extend elements on your background layer behind your other layers, otherwise the camera angle will sometimes let you see a gap to the left or right of a background wall and the layer in front of it (for example). It can be just a few tiles extended, unless you have tiles infront that are transparent and reveal behind it. |-|Tile Editor= Full article here [[Tile Editor]]. {| class="wikitable" |+ Tile editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Select tile category |- | W,S || Select tile in current category |- | LMB || Place tile under cursor |- | RMB || Erase tile under cursor |- | F (hold) || Use a 3x3 brush for materials |- | V (hold) || Use a 5x5 brush for materials |- | Tab+x+c || Clears all tiles |- | L || Change active layer (1, 2, 3, loop back to 1) |- | E || Sets default material of the room to the currently selected material |- | F (hold) || Enables force placing selected tile (ignoring geometry, erasing colliding tiles) |- | G (hold) || Enables force placing selected tile (forcing appropriate geometry for the tile, erasing colliding tiles) |- | Q || "Eyedropper" (selects tile/material hovered over) |} |-|Effect Editor= Full article here [[Effects Editor]]. {| class="wikitable" |+ Effect library keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Select effect category |- | W,S || Select effect in current category |- | E || Switches to editing applied effects |- | Space || Adds selected effect to the stack |} {| class="wikitable" |+ Applied effect keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,S || Scroll through the effect stack |- | N || Switch to effect library |- | Space || Edit selected effect in the stack |} Effect editing: {| class="wikitable" |+ Effect editing keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Scroll through options in the effect's menu |- | W,S || Changes the current effect's menu |- | Space || Activates selected option in the effect's menu |- | LMB || Paints effect in the level |- | RMB || Erases effect in the level |- | R || Brush size up |- | F || Brush size down |- | E || Switch to effect stack |- | N || Switch to effect library |} |-|Camera Editor= Full article here Camera Editor. N - New camera, spawns held by mouse E - grab a camera if none is held D - Delete held camera P - Place held camera |-|Light editor= Full article here [[Light Editor]]. {| class="wikitable" |+ Light editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,A,S,D || Scale current light shape |- | Q,E || Rotate current light shape |- | Z || Toggle between drawing and erasing light |- | LMB || Paint light |- | RMB (hold) || Rotate light shape in direction of mouse ( does not paint it.) |- | R,F || Scroll through light shape library |- | J,L || Change angle of light source |- | I,K || Change distance of light source |} |-|Prop Editor= Full article here [[Prop Editor]]. {| class="wikitable" |+ Prop editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A, D || Changes prop library's category |- | W, S || Scrolls through props in current category |- | LMB || Place current prop |- | V (hold) || LMB erases highlighted prop |- | Q,E || Rotate prop left and right |- | Space (hold) || Speed up rotation |- | Y,G,H,J || Stretch prop |- | T || Reset prop stretching |- | R || reset stretching, and rotation |- | Y, H || (on wire/tube props) increases or decreases prop's physics node count. Less means more taught, more means more loose |- | X || Pause wire/tube physics |- | Tab+X+C || clear all props |- | B || Click mouse left to set the highlighted prop as the currently selected prop |- | L || Change layer |- | RMB || Cycle depth in current layer (10 sublevels). |- | Space + RMB || Cycle depth in current layer, reverse direction. |- | U,I,O,P (hold) || Freeform stretch by one of the corners (U - top right, I - bottom right, O - bottom left, and P - top left.) |- | K || resets freeform stretching. |- | N || Switches to editing properties menu of the prop. Things like forcing certain graffiti to be drawn instead of a random one. |- | M (hold) || LMB opens properties of an already placed prop instead of placing a prop (same menu as above) |- | Z || Changes prop color |- | F + LMB/RMB || Changes between prop variants. This only applies to certain props. |} |-|Environment Editor= {| class="wikitable" |+ Environment editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | L || Set water level to mouse pointer |- | F || Toggles between drawing water above the first layer or below it. |- | W || Toggle water on level |} </tabber> == Crash Avoidance and Editor Quirks == Due to the editor being extremely user unfriendly, you are likely to run into various crashes without warning. This is a list of various things to avoid doing. === Crashes: === Do not switch to editing applied effects in the Effects Editor when there are none. The switch will be invisible, and attempting to use the space bar to select something from there will crash the Level Editor. Some effects have very specific conditions and cause issues when rendering, Effects include: Thick Roots, and Shadow Plants. these ones can be okayed through until it renders.) Be sure to remove tiles from parts of a room that will be removed if you resize the room to cut those areas out, those tiles are still recorded, and will crash renders instantly. props are the exact same as above Never render with no cameras. It will crash. Always move the prop menu into an actual category when you open it, it keeps the last menu used, and crashes if you select any entry that is not a real prop. (EX: it will have the effects menu, or tile menu.) If you are using the Mirrored tile placer, in the geometry editor. Placing poles, with the other side of the mirrored brush being outside of the room, will crash the editor. === Quirks: === The main menu is a mess when you return from using the Light Editor or the Environment Editor. Just change to any other editor (geometry or tiles, and back to main menu) to clean it. This is not a crash, but will help prevent confusion if you know to expect this. To use the Move and Move Mirror tools in the editor, you must first select them, and then move your mouse outside of the room itself, before it will respond to your inputs. Usually you will only need to put your mouse over the editor, but in larger rooms, this is often an issue, as the room is "behind" the menu, and thus only changes tool selection. The editor still receives inputs if you only tab out using alt-tab. When viewing another window, it's important to always minimize the editor, because there are many things that can go wrong if you're randomly clicking in the editor. (Requires more confirmation) The screen during rendering should usually show the map being rendered, but it may not. In the task manager, The Rain World Editor is under the tab Adobe Projector. Sometimes the reason it is not showing is a second application called "Print driver host for applications". Closing the application seems to fix the issue. The window for the application may be too big to fit on screen, and cannot be fixed since reaching the top bar or right clicking cannot be accessed to move the window. === Demo and Tutorial Videos === Region Developer Kaeporo created a tutorial for creating levels in and out of the level editor: {{#ev:youtube|YQ0DO-fmPCE|||||urlargs=""}} Mod community member Sacretis also put together a demonstration video, this time covering the creation of a room from scratch to visual polish (massively sped up for the sake of time): {{#ev:youtube|sEE3X1izaJA|||||urlargs=""}} fa12c871e93b943657e4d2e965e59a27433e990e User:Topicular 2 170 373 2023-02-11T13:36:49Z Topicular 81 create user page wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 Warp 0 128 374 330 2023-02-13T21:21:44Z Morebagels 84 corrected lust to list wikitext text/x-wiki Warp is a utility mod for Rain World that you can use to easily teleport to different rooms and regions. It is particularly useful for testing mods and [[CRS|region packs]]. Download and install Warp from [https://www.raindb.net/ RainDB] or [https://github.com/LeeMoriya/Warp/releases/latest Warp's GitHub page]. == Usage == [[File:WarpMenu.png|thumb|Region buttons are shown on the left, room buttons are shown on the right. There are also settings for different colour codings and order schemes. ]] Install Warp using [[BepInEx]], and then Warp menu will appear in the in-game pause menu. Clicking on a room button will teleport the player to the room's first entrance pipe (numbered 0). Clicking on a region button (other than the one the player is currently in) will load the region and show a list of its rooms instead. The loading process may take a few seconds if the region is particularly large. === Issues When Warping === If the region doesn't load then there is likely an issue with the region or room you are trying to warp to. Check your [[Logs|exceptionLog]] for errors and review any recent changes you made to the region/rooms. If you are making a custom region, make sure there are no errors with room connections in your World file, or problems with your room's geometry (e.g. invalid pipe entrances). If you have installed/uninstalled a new region, make sure you have started the game from a fresh save since that region was added or the game may freeze when switching regions or resting in a shelter. == Custom Den Position == Warp features and option to change which room the game considers as the player's den position (the room in which they start the next cycle). Note that if you're using [[Extended Dev Tools]], the 'Start Map' parameter in the <code>edtSetup.json</code> must be empty or it will override Warp. * Hold Shift and click a room name to set the den position. * Press C to reset the den position to its default. == Custom Regions Support == Warp supports [[CRS|Garrakx's Custom Regions Support]] mod which allows for easier creation of new regions and region changes, and will load new rooms from within your CustomResources folder. Below is how room lists are currently generated: === Current Region === The list of rooms for the region you are currently in are taken directly from the list of loaded AbstractRooms. === Different Regions === When you click on a button for a different region, the room list is generated like so: # Rooms are added to the room list from the vanilla World folder. # Each Rooms folder found in CustomResources is scanned and rooms not already in the list are added. At the moment, this means that if a region pack is present in your CustomResources folder but has been manually disabled in its regionInfo.json, rooms from this folder will be regardless and clicking on them will do nothing. This is also technically the case for any region pack that removes rooms. [[Category:Utilities and Tools]] 6a803a6c07960b6ff32edcf5b74c95e5bf2b9959 Talk:Main Page 1 171 375 2023-02-15T03:25:59Z Archangel 71 created wikitext text/x-wiki Talk about the main page idk 4beed163d458bc9c2aa42794a77e17a1139e90ae 376 375 2023-02-15T03:27:43Z Archangel 71 /* Not enough information! */ new section wikitext text/x-wiki Talk about the main page idk == Not enough information! == I want to learn how to mod this game, but there's no information! I don't know where to go to start modding, where are the docs, where is anything I want to see? Please overhaul this page. bc432e3667770f75a1cef894479d90f4e1b8cbaa Talk:Legacy Mod Installation 1 173 379 2023-03-08T14:37:22Z Bent is broken 110 Created page with "Just asking, how do you mod on switch? - bent" wikitext text/x-wiki Just asking, how do you mod on switch? - bent bb29d2b2f426240d288912fa230119ffa1849868 410 379 2023-03-30T20:53:52Z Thalber 3 Thalber moved page [[Talk:Installing Mods]] to [[Talk:Legacy Mod Installation]] without leaving a redirect wikitext text/x-wiki Just asking, how do you mod on switch? - bent bb29d2b2f426240d288912fa230119ffa1849868 Learning C Sharp 0 174 380 2023-03-20T23:09:05Z Cashewww 2 Created page with "C# is a general-purpose programming language popular in game development. More information about the language can be found [https://en.wikipedia.org/wiki/C%20Sharp%20(programming%20language) on its Wikipedia page]. Rain World's code is written in C#. As per the standard C# development life cycle, each release of the game is compiled into .NET's Common Intermediate Language (CIL) which is stored in Dynamic Link Library (DLL) files. To read an approximation of the game's..." wikitext text/x-wiki C# is a general-purpose programming language popular in game development. More information about the language can be found [https://en.wikipedia.org/wiki/C%20Sharp%20(programming%20language) on its Wikipedia page]. Rain World's code is written in C#. As per the standard C# development life cycle, each release of the game is compiled into .NET's Common Intermediate Language (CIL) which is stored in Dynamic Link Library (DLL) files. To read an approximation of the game's code, a .NET decompiler is used to decompile the CIL into C# (or sometimes to view the IL when IL editing). As such, code mods are also written in C#, and so an understanding of C# is '''essential''' for code modding. == Beginner Guides == * [https://www.w3schools.com/cs/index.php w3schools] - if you're new to programming * [https://learnxinyminutes.com/docs/csharp/ Learn X in Y minutes] - if some experience in another language and OOP * [https://dotnet.microsoft.com/en-us/learn/csharp Microsoft: Learn C#] - more comprehensive == Important Topics == * [https://www.geeksforgeeks.org/scope-of-variables-in-c-sharp/ GeeksForGeeks: Scope in C#] * [https://isaaccomputerscience.org/topics/object_oriented_programming Isaac Computer Science: Object-Oriented Programming (OOP)] == Other == * [https://isaaccomputerscience.org/topics/a_level?examBoard=all&stage=all#aqa Isaac Computer Science - AQA A-level Computer Science] ** Covers content for the AQA A-level Computer Science (UK exam) specification. It's not C# specific, but chapters 4.1 to 4.3 (and to some extent 4.4) are nice resources for getting to grips with programming. 76b3be949b7fb6fb4ced146c0c73ce819fd4dd70 381 380 2023-03-20T23:13:57Z Cashewww 2 added to code mods category wikitext text/x-wiki C# is a general-purpose programming language popular in game development. More information about the language can be found [https://en.wikipedia.org/wiki/C%20Sharp%20(programming%20language) on its Wikipedia page]. Rain World's code is written in C#. As per the standard C# development life cycle, each release of the game is compiled into .NET's Common Intermediate Language (CIL) which is stored in Dynamic Link Library (DLL) files. To read an approximation of the game's code, a .NET decompiler is used to decompile the CIL into C# (or sometimes to view the IL when IL editing). As such, code mods are also written in C#, and so an understanding of C# is '''essential''' for code modding. == Beginner Guides == * [https://www.w3schools.com/cs/index.php w3schools] - if you're new to programming * [https://learnxinyminutes.com/docs/csharp/ Learn X in Y minutes] - if some experience in another language and OOP * [https://dotnet.microsoft.com/en-us/learn/csharp Microsoft: Learn C#] - more comprehensive == Important Topics == * [https://www.geeksforgeeks.org/scope-of-variables-in-c-sharp/ GeeksForGeeks: Scope in C#] * [https://isaaccomputerscience.org/topics/object_oriented_programming Isaac Computer Science: Object-Oriented Programming (OOP)] == Other == * [https://isaaccomputerscience.org/topics/a_level?examBoard=all&stage=all#aqa Isaac Computer Science - AQA A-level Computer Science] ** Covers content for the AQA A-level Computer Science (UK exam) specification. It's not C# specific, but chapters 4.1 to 4.3 (and to some extent 4.4) are nice resources for getting to grips with programming. [[Category:Code Mods]] 0d7076d9bfb12656de003010fe02159dd984d7c6 SlugBase 0 127 382 302 2023-03-20T23:17:57Z Cashewww 2 updated slugbase wiki link wikitext text/x-wiki {{todo|target=article}} SlugBase is a framework created by SlimeCubed for adding additional slugcat characters to Rain World, with an emphasis on compatibility. It allows modders to tweak their character's common stats and colours, and is useful for as a base for new characters that have unique abilities (which can be achieved using [[BepInPlugins|hooking]]). SlugBase can be downloaded from [https://github.com/SlimeCubed/SlugBase/releases/latest here]. SlugBase's documentation can be found [https://slimecubed.github.io/slugbase/ here]. [[Category:Code Mods]] [[Category:Dependencies]] 9a4953794a9979900fbae52c1853b0ca3c217e79 bepinplugins 0 175 383 2023-03-21T20:11:44Z Cashewww 2 Redirected page to [[BepInPlugins]] wikitext text/x-wiki #REDIRECT [[BepInPlugins]] 6497f9a732b53d4ed81a88716476dd89008cbdf5 Threat Music File Format 0 176 385 2023-03-26T15:42:44Z Forthbridge 91 Created page with "Threat music utilizes a <code>xx.txt</code> file named after the region it plays in to define both the track layers and the order in which they play depending on the threat level. To explain the format and its quirks, lets take a look at Chimney Canopy's threat file, <code>cc.txt</code>: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOI..." wikitext text/x-wiki Threat music utilizes a <code>xx.txt</code> file named after the region it plays in to define both the track layers and the order in which they play depending on the threat level. To explain the format and its quirks, lets take a look at Chimney Canopy's threat file, <code>cc.txt</code>: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> First, let's focus first on just the top section: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA </syntaxhighlight> Here, the tracks that will be used are defined. First comes the file name of the track (without the extension), such as <code>TH_CC - KICK.ogg</code>, followed by a set of flags. The following flags, for example <code>NEUTRAL <PA></code>, are misleading - <u><b>they are unused and do not affect how the track is played in any way</u></b>. For completeness, here are all of the possible flags: <syntaxhighlight> NEUTRAL HIGHKARMA DANGER Can be followed by: <PA> Internally sets 'remainInPanicMode', however this field is not used elsewhere. Likely intended to cause the target track to play for longer after the threat has gone down, but it is unimplemented. </syntaxhighlight> For your tracks, you can simply use <code>NEUTRAL</code>. 75ea1bf0ace1bcb69f05eb9c114e9d4c9468604d 386 385 2023-03-26T17:10:02Z Forthbridge 91 wikitext text/x-wiki Threat music utilizes a <code>xx.txt</code> file named after the region it plays in to define both the track layers and the order in which they play depending on the threat level. To explain the format and its quirks, lets take a look at Chimney Canopy's threat file, <code>cc.txt</code>: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> == Defining Tracks == First, let's focus first on just the top section: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA </syntaxhighlight> Here, the tracks that will be used are defined. First comes the file name of the track (without the extension), such as <code>TH_CC - KICK.ogg</code>, followed by a set of flags. The following flags, for example <code>NEUTRAL <PA></code>, are misleading - <u><b>they are unused and do not affect how the track is played in any way</u></b>. For completeness, here are all of the possible flags: <syntaxhighlight> NEUTRAL HIGHKARMA DANGER Can be followed by: <PA> Internally sets 'remainInPanicMode', however this field is not used elsewhere. Likely intended to cause the target track to play for longer after the threat has gone down, but it is unimplemented. </syntaxhighlight> For defining your tracks, you can simply use <code>NEUTRAL</code>. == Defining Tracks == == Folder Structure == With your <code>xx.txt</code> file complete, you can move onto setting up the necessary folder structure to have your tracks be loaded and played in-game! First, you will need the following file structure 5f07d02007dd351c7582eb74d8cd718fe0fd1ebe 387 386 2023-03-26T17:13:16Z Forthbridge 91 wikitext text/x-wiki {{todo}} Threat music utilizes a <code>xx.txt</code> file named after the region it plays in to define both the track layers and the order in which they play depending on the threat level. To explain the format and its quirks, lets take a look at Chimney Canopy's threat file, <code>cc.txt</code>: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> == Defining Tracks == First, let's focus first on just the top section: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA </syntaxhighlight> Here, the tracks that will be used are defined. First comes the file name of the track (without the extension), such as <code>TH_CC - KICK.ogg</code>, followed by a set of flags. The following flags, for example <code>NEUTRAL <PA></code>, are misleading - <u><b>they are unused and do not affect how the track is played in any way</u></b>. For completeness, here are all of the possible flags: <syntaxhighlight> NEUTRAL HIGHKARMA DANGER Can be followed by: <PA> Internally sets 'remainInPanicMode', however this field is not used elsewhere. Likely intended to cause the target track to play for longer after the threat has gone down, but it is unimplemented. </syntaxhighlight> For defining your tracks, you can simply use <code>NEUTRAL</code>. == Defining Layers == == Folder Structure == With your <code>xx.txt</code> file complete, you can move onto setting up the necessary folder structure to have your tracks be loaded and played in-game! First, you will need the following file structure 2d1e7bf8941db0432f1b7388f4cb5219b13acaaa 388 387 2023-03-26T17:15:38Z Forthbridge 91 wikitext text/x-wiki {{todo}} Threat music utilizes a <code>xx.txt</code> file named after the region it plays in to define both the track layers and the order in which they play depending on the threat level. To explain the format and its quirks, lets take a look at Chimney Canopy's threat file, <code>cc.txt</code>: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> == Defining Tracks == First, let's focus first on just the top section: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA </syntaxhighlight> Here, the tracks that will be used are defined. First comes the file name of the track (without the extension), such as <code>TH_CC - KICK.ogg</code>, followed by a set of flags. The flags themselves, for example <code>NEUTRAL <PA></code>, are misleading - <u><b>they are unused and do not affect how the track is played in any way</u></b>. For completeness, here are all of the possible flags: <syntaxhighlight> NEUTRAL HIGHKARMA DANGER Any flag may be followed by: <PA> ...which internally sets 'remainInPanicMode', however this field is unused. Likely intended to cause the target track to play for longer after the threat has gone down, but it is unimplemented. </syntaxhighlight> For defining your tracks, you can simply use <code>NEUTRAL</code>. == Defining Layers == To see how to define layers, we can look at the second section: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> == Folder Structure == With your <code>xx.txt</code> file complete, you can move onto setting up the necessary folder structure to have your tracks be loaded and played in-game! First, you will need the following file structure: 73fc8fde5b53f1f812701f1e6eecc61a78f30f3c 391 388 2023-03-28T15:10:16Z Forthbridge 91 /* Defining Layers */ wikitext text/x-wiki {{todo}} Threat music utilizes a <code>xx.txt</code> file named after the region it plays in to define both the track layers and the order in which they play depending on the threat level. To explain the format and its quirks, lets take a look at Chimney Canopy's threat file, <code>cc.txt</code>: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> == Defining Tracks == First, let's focus first on just the top section: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA </syntaxhighlight> Here, the tracks that will be used are defined. First comes the file name of the track (without the extension), such as <code>TH_CC - KICK.ogg</code>, followed by a set of flags. The flags themselves, for example <code>NEUTRAL <PA></code>, are misleading - <u><b>they are unused and do not affect how the track is played in any way</u></b>. For completeness, here are all of the possible flags: <syntaxhighlight> NEUTRAL HIGHKARMA DANGER Any flag may be followed by: <PA> ...which internally sets 'remainInPanicMode', however this field is unused. Likely intended to cause the target track to play for longer after the threat has gone down, but it is unimplemented. </syntaxhighlight> For defining your tracks, you can simply use <code>NEUTRAL</code>. == Defining Layers == To see how to define layers, we can look at the second section: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> Here, layers are defined in increasing level of threat, with minimum threat at the top and maximum threat at the bottom. As the threat increases, more layers are added - there is no practical limit on the number of layers, so you can have as many as you like! Let's take a look at just one layer: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE </syntaxhighlight> Here, we can see this layer has the tracks <code>TH_CC - KICK</code>, <code>TH_CC - PERC1</code>, and <code>TH_CC - NOISE</code>. When a layer has multiple tracks, each track can be treated as a sort of 'sub-layer' in the sense that the track that plays depends on the threat level. The key thing to note is that the order that the tracks in a layer play is randomized whenever there is a silence (when the threat music stops). So, for instance, the layer we are looking at may play the tracks in the following order, from low to high threat: <syntaxhighlight> 1. TH_CC - KICK 2. TH_CC - PERC1 3. TH_CC - NOISE </syntaxhighlight> Then, there is a silence - the tracks in the layers are reshuffled, so the new order may look something like this: <syntaxhighlight> 1. TH_CC - NOISE 2. TH_CC - KICK 3. TH_CC - PERC1 </syntaxhighlight> Layers, unlike tracks, will always maintain their order. So the following: <syntaxhighlight> Layer : NOISE Layer : TH_CC - KICK Layer : TH_CC - PERC1 </syntaxhighlight> Will always play in the order <code>NOISE, KICK, PERC1</code>. <b>As a last note on layers, the syntax you see in the existing threat files is somewhat redundant.</b> Reading from top to bottom, each layer is defined only by what tracks are added relative to the last layer. Therefore, the following: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> Is equivalent to: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - PERC2 Layer : TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - ARPS </syntaxhighlight> == Folder Structure == With your <code>xx.txt</code> file complete, you can move onto setting up the necessary folder structure to have your tracks be loaded and played in-game! First, you will need the following file structure: a867e72dbd13bda3d7004e40cb9b77f3bf5b4b65 392 391 2023-03-28T15:15:05Z Forthbridge 91 /* Defining Layers */ wikitext text/x-wiki {{todo}} Threat music utilizes a <code>xx.txt</code> file named after the region it plays in to define both the track layers and the order in which they play depending on the threat level. To explain the format and its quirks, lets take a look at Chimney Canopy's threat file, <code>cc.txt</code>: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> == Defining Tracks == First, let's focus first on just the top section: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA </syntaxhighlight> Here, the tracks that will be used are defined. First comes the file name of the track (without the extension), such as <code>TH_CC - KICK.ogg</code>, followed by a set of flags. The flags themselves, for example <code>NEUTRAL <PA></code>, are misleading - <u><b>they are unused and do not affect how the track is played in any way</u></b>. For completeness, here are all of the possible flags: <syntaxhighlight> NEUTRAL HIGHKARMA DANGER Any flag may be followed by: <PA> ...which internally sets 'remainInPanicMode', however this field is unused. Likely intended to cause the target track to play for longer after the threat has gone down, but it is unimplemented. </syntaxhighlight> For defining your tracks, you can simply use <code>NEUTRAL</code>. == Defining Layers == To see how to define layers, we can look at the second section: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> Here, layers are defined in increasing level of threat, with minimum threat at the top and maximum threat at the bottom. As the threat increases, more layers are added - there is no practical limit on the number of layers, so you can have as many as you like! Let's take a look at just one layer: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE </syntaxhighlight> Here, we can see this layer has the tracks <code>TH_CC - KICK</code>, <code>TH_CC - PERC1</code>, and <code>TH_CC - NOISE</code>. When a layer has multiple tracks, each track can be treated as a sort of 'sub-layer' in the sense that the track that plays depends on the threat level. The key thing to note is that the order that the tracks in a layer play is randomized whenever there is a silence (when the threat music stops). So, for instance, the layer we are looking at may play the tracks in the following order, from low to high threat: <syntaxhighlight> 1. TH_CC - KICK 2. TH_CC - PERC1 3. TH_CC - NOISE </syntaxhighlight> Then, there is a silence - the tracks in the layers are reshuffled, so the new order may look something like this: <syntaxhighlight> 1. TH_CC - NOISE 2. TH_CC - KICK 3. TH_CC - PERC1 </syntaxhighlight> Layers, unlike tracks, will always maintain their order. So the following: <syntaxhighlight> Layer : NOISE Layer : TH_CC - KICK Layer : TH_CC - PERC1 </syntaxhighlight> Will always play in the order <code>NOISE, KICK, PERC1</code>. <u><b>As a last note on layers, the syntax you see in the existing threat files is somewhat redundant.</b></u> Reading from top to bottom, each layer is defined only by what tracks are added relative to the last layer. Therefore, the following: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> Is actually equivalent to: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - PERC2 Layer : TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - ARPS </syntaxhighlight> ...which you might find easier to read and use. To summarize with the above example, the layers will be played in order from top to bottom, low threat to high threat. The tracks under layers 1 and 3 will be played in a random order, whereas 2 and 4 will always play the same track, as they have only one. == Folder Structure == With your <code>xx.txt</code> file complete, you can move onto setting up the necessary folder structure to have your tracks be loaded and played in-game! First, you will need the following file structure: 215f61adf46a171959ab61e9c46e5e44c3cf0e1a 393 392 2023-03-28T15:20:51Z Forthbridge 91 /* Defining Layers */ wikitext text/x-wiki {{todo}} Threat music utilizes a <code>xx.txt</code> file named after the region it plays in to define both the track layers and the order in which they play depending on the threat level. To explain the format and its quirks, lets take a look at Chimney Canopy's threat file, <code>cc.txt</code>: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> == Defining Tracks == First, let's focus first on just the top section: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA </syntaxhighlight> Here, the tracks that will be used are defined. First comes the file name of the track (without the extension), such as <code>TH_CC - KICK.ogg</code>, followed by a set of flags. The flags themselves, for example <code>NEUTRAL <PA></code>, are misleading - <u><b>they are unused and do not affect how the track is played in any way</u></b>. For completeness, here are all of the possible flags: <syntaxhighlight> NEUTRAL HIGHKARMA DANGER Any flag may be followed by: <PA> ...which internally sets 'remainInPanicMode', however this field is unused. Likely intended to cause the target track to play for longer after the threat has gone down, but it is unimplemented. </syntaxhighlight> For defining your tracks, you can simply use <code>NEUTRAL</code>. == Defining Layers == To see how to define layers, we can look at the second section: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> Here, layers are defined in increasing level of threat, with minimum threat at the top and maximum threat at the bottom. As the threat increases, more layers are added - there is no practical limit on the number of layers, so you can have as many as you like! Let's take a look at just one layer: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE </syntaxhighlight> Here, we can see this layer has the tracks <code>TH_CC - KICK</code>, <code>TH_CC - PERC1</code>, and <code>TH_CC - NOISE</code>. When a layer has multiple tracks, each track can be treated as a sort of 'sub-layer' in the sense that the track that plays depends on the threat level. The key thing to note is that the order that the tracks in a layer play is randomized whenever there is a silence (when the threat music stops). So, for instance, the layer we are looking at may play the tracks in the following order, from low to high threat: <syntaxhighlight> 1. TH_CC - KICK 2. TH_CC - PERC1 3. TH_CC - NOISE </syntaxhighlight> Then, there is a silence - the tracks in the layers are reshuffled, so the new order may look something like this: <syntaxhighlight> 1. TH_CC - NOISE 2. TH_CC - KICK 3. TH_CC - PERC1 </syntaxhighlight> Layers, unlike tracks, will always maintain their order. So the following: <syntaxhighlight> Layer : NOISE Layer : TH_CC - KICK Layer : TH_CC - PERC1 </syntaxhighlight> Will always play in the order <code>NOISE, KICK, PERC1</code>. <u><b>As a last note on layers, the syntax you see in the existing threat files is somewhat redundant.</b></u> Reading from top to bottom, each layer is defined only by what tracks are added relative to the last layer. Therefore, the following: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> Is actually equivalent to: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - PERC2 Layer : TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - ARPS </syntaxhighlight> ...which you might find easier to read and use. To summarize with the above example, the layers will be played in order from top to bottom, low threat to high threat. The tracks under layers 1 and 3 will be played in a random order, whereas 2 and 4 will always play the same track, as they have only one. == Additional Layer Syntax == Some additional syntax exists for restricting when certain tracks within a layer may play: * Prefix an track in a layer with {D} to make it only play during the daytime (redundant/irrelevant if region doesn't use day-night cycles) * Prefix an track in a layer with {N} to make it only play during the nighttime (irrelevant if the region doesn't use day-night cycles) * Prefix an track in a layer with {M} to make it only play while the player is under the influence of mushrooms. * Prefix an track with a subregion name between <code>{}</code> to make it only play in that subregion. Multiple subregions can be specified by separating them with the pipe character (<code>|</code>). For example: <syntaxhighlight> Layer : {D}TH_CC - KICK Layer : {N}TH_CC - PERC2 Layer : {M}TH_CC - SNARE Layer : {Chimney Canopy|The Gutter}TH_CC - ARPS </syntaxhighlight> == Folder Structure == With your <code>xx.txt</code> file complete, you can move onto setting up the necessary folder structure to have your tracks be loaded and played in-game! First, you will need the following file structure: 47dab3f3c0c5d67d193575de4fc7099598857162 394 393 2023-03-28T15:28:06Z Forthbridge 91 /* Folder Structure */ wikitext text/x-wiki {{todo}} Threat music utilizes a <code>xx.txt</code> file named after the region it plays in to define both the track layers and the order in which they play depending on the threat level. To explain the format and its quirks, lets take a look at Chimney Canopy's threat file, <code>cc.txt</code>: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> == Defining Tracks == First, let's focus first on just the top section: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA </syntaxhighlight> Here, the tracks that will be used are defined. First comes the file name of the track (without the extension), such as <code>TH_CC - KICK.ogg</code>, followed by a set of flags. The flags themselves, for example <code>NEUTRAL <PA></code>, are misleading - <u><b>they are unused and do not affect how the track is played in any way</u></b>. For completeness, here are all of the possible flags: <syntaxhighlight> NEUTRAL HIGHKARMA DANGER Any flag may be followed by: <PA> ...which internally sets 'remainInPanicMode', however this field is unused. Likely intended to cause the target track to play for longer after the threat has gone down, but it is unimplemented. </syntaxhighlight> For defining your tracks, you can simply use <code>NEUTRAL</code>. == Defining Layers == To see how to define layers, we can look at the second section: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> Here, layers are defined in increasing level of threat, with minimum threat at the top and maximum threat at the bottom. As the threat increases, more layers are added - there is no practical limit on the number of layers, so you can have as many as you like! Let's take a look at just one layer: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE </syntaxhighlight> Here, we can see this layer has the tracks <code>TH_CC - KICK</code>, <code>TH_CC - PERC1</code>, and <code>TH_CC - NOISE</code>. When a layer has multiple tracks, each track can be treated as a sort of 'sub-layer' in the sense that the track that plays depends on the threat level. The key thing to note is that the order that the tracks in a layer play is randomized whenever there is a silence (when the threat music stops). So, for instance, the layer we are looking at may play the tracks in the following order, from low to high threat: <syntaxhighlight> 1. TH_CC - KICK 2. TH_CC - PERC1 3. TH_CC - NOISE </syntaxhighlight> Then, there is a silence - the tracks in the layers are reshuffled, so the new order may look something like this: <syntaxhighlight> 1. TH_CC - NOISE 2. TH_CC - KICK 3. TH_CC - PERC1 </syntaxhighlight> Layers, unlike tracks, will always maintain their order. So the following: <syntaxhighlight> Layer : NOISE Layer : TH_CC - KICK Layer : TH_CC - PERC1 </syntaxhighlight> Will always play in the order <code>NOISE, KICK, PERC1</code>. <u><b>As a last note on layers, the syntax you see in the existing threat files is somewhat redundant.</b></u> Reading from top to bottom, each layer is defined only by what tracks are added relative to the last layer. Therefore, the following: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> Is actually equivalent to: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - PERC2 Layer : TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - ARPS </syntaxhighlight> ...which you might find easier to read and use. To summarize with the above example, the layers will be played in order from top to bottom, low threat to high threat. The tracks under layers 1 and 3 will be played in a random order, whereas 2 and 4 will always play the same track, as they have only one. == Additional Layer Syntax == Some additional syntax exists for restricting when certain tracks within a layer may play: * Prefix an track in a layer with {D} to make it only play during the daytime (redundant/irrelevant if region doesn't use day-night cycles) * Prefix an track in a layer with {N} to make it only play during the nighttime (irrelevant if the region doesn't use day-night cycles) * Prefix an track in a layer with {M} to make it only play while the player is under the influence of mushrooms. * Prefix an track with a subregion name between <code>{}</code> to make it only play in that subregion. Multiple subregions can be specified by separating them with the pipe character (<code>|</code>). For example: <syntaxhighlight> Layer : {D}TH_CC - KICK Layer : {N}TH_CC - PERC2 Layer : {M}TH_CC - SNARE Layer : {Chimney Canopy|The Gutter}TH_CC - ARPS </syntaxhighlight> == Folder Structure == With your <code>xx.txt</code> file complete, you can move onto setting up the necessary folder structure to have your tracks be loaded and played in-game! First, you will need the following file structure under your mod's root directory: <pre>music/procedural</pre> Place your <code>xx.txt</code> within <code>procedural</code>, ensuring <code>xx</code> matches your desired region's acronym. Next, you must add the sound files themselves. There are only 2 conditions: * Sound files must be in <code>.ogg</code> format to be recognized and loaded by the game. * The base name of the sound file (without the extension) must match a track you defined in your <code>xx.txt</code> file. After that, you should be done - warp to your custom region, get into some danger and enjoy your custom threat music in-game! 41248975716bba8901c659ed7ee82f9c4addae29 395 394 2023-03-28T15:31:26Z Forthbridge 91 wikitext text/x-wiki Threat music utilizes a <code>xx.txt</code> file named after the region it plays in to define both the track layers and the order in which they play depending on the threat level. This guide will go over adding custom threat music to a ''new'' region - if you want to replace the threat music in an existing region, the process is largely the same, however it will require an understanding of modification files and their format: [[Downpour Reference/Modification_Files]] To explain the format and its quirks, lets take a look at Chimney Canopy's threat file, <code>cc.txt</code>: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> == Defining Tracks == First, let's focus first on just the top section: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA </syntaxhighlight> Here, the tracks that will be used are defined. First comes the file name of the track (without the extension), such as <code>TH_CC - KICK.ogg</code>, followed by a set of flags. The flags themselves, for example <code>NEUTRAL <PA></code>, are misleading - <u><b>they are unused and do not affect how the track is played in any way</u></b>. For completeness, here are all of the possible flags: <syntaxhighlight> NEUTRAL HIGHKARMA DANGER Any flag may be followed by: <PA> ...which internally sets 'remainInPanicMode', however this field is unused. Likely intended to cause the target track to play for longer after the threat has gone down, but it is unimplemented. </syntaxhighlight> For defining your tracks, you can simply use <code>NEUTRAL</code>. == Defining Layers == To see how to define layers, we can look at the second section: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> Here, layers are defined in increasing level of threat, with minimum threat at the top and maximum threat at the bottom. As the threat increases, more layers are added - there is no practical limit on the number of layers, so you can have as many as you like! Let's take a look at just one layer: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE </syntaxhighlight> Here, we can see this layer has the tracks <code>TH_CC - KICK</code>, <code>TH_CC - PERC1</code>, and <code>TH_CC - NOISE</code>. When a layer has multiple tracks, each track can be treated as a sort of 'sub-layer' in the sense that the track that plays depends on the threat level. The key thing to note is that the order that the tracks in a layer play is randomized whenever there is a silence (when the threat music stops). So, for instance, the layer we are looking at may play the tracks in the following order, from low to high threat: <syntaxhighlight> 1. TH_CC - KICK 2. TH_CC - PERC1 3. TH_CC - NOISE </syntaxhighlight> Then, there is a silence - the tracks in the layers are reshuffled, so the new order may look something like this: <syntaxhighlight> 1. TH_CC - NOISE 2. TH_CC - KICK 3. TH_CC - PERC1 </syntaxhighlight> Layers, unlike tracks, will always maintain their order. So the following: <syntaxhighlight> Layer : NOISE Layer : TH_CC - KICK Layer : TH_CC - PERC1 </syntaxhighlight> Will always play in the order <code>NOISE, KICK, PERC1</code>. <u><b>As a last note on layers, the syntax you see in the existing threat files is somewhat redundant.</b></u> Reading from top to bottom, each layer is defined only by what tracks are added relative to the last layer. Therefore, the following: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> Is actually equivalent to: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - PERC2 Layer : TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - ARPS </syntaxhighlight> ...which you might find easier to read and use. To summarize with the above example, the layers will be played in order from top to bottom, low threat to high threat. The tracks under layers 1 and 3 will be played in a random order, whereas 2 and 4 will always play the same track, as they have only one. == Additional Layer Syntax == Some additional syntax exists for restricting when certain tracks within a layer may play: * Prefix an track in a layer with {D} to make it only play during the daytime (redundant/irrelevant if region doesn't use day-night cycles) * Prefix an track in a layer with {N} to make it only play during the nighttime (irrelevant if the region doesn't use day-night cycles) * Prefix an track in a layer with {M} to make it only play while the player is under the influence of mushrooms. * Prefix an track with a subregion name between <code>{}</code> to make it only play in that subregion. Multiple subregions can be specified by separating them with the pipe character (<code>|</code>). For example: <syntaxhighlight> Layer : {D}TH_CC - KICK Layer : {N}TH_CC - PERC2 Layer : {M}TH_CC - SNARE Layer : {Chimney Canopy|The Gutter}TH_CC - ARPS </syntaxhighlight> == Folder Structure == With your <code>xx.txt</code> file complete, you can move onto setting up the necessary folder structure to have your tracks be loaded and played in-game! First, you will need the following file structure under your mod's root directory: <pre>music/procedural</pre> Place your <code>xx.txt</code> within <code>procedural</code>, ensuring <code>xx</code> matches your desired region's acronym. Next, you must add the sound files themselves. There are only 2 conditions: * Sound files must be in <code>.ogg</code> format to be recognized and loaded by the game. * The base name of the sound file (without the extension) must match a track you defined in your <code>xx.txt</code> file. After that, you should be done - warp to your custom region, get into some danger and enjoy your custom threat music in-game! d463ebdd8b912738ca7feaae5955e9889d9f4868 396 395 2023-03-28T16:26:11Z Forthbridge 91 /* Defining Layers */ wikitext text/x-wiki Threat music utilizes a <code>xx.txt</code> file named after the region it plays in to define both the track layers and the order in which they play depending on the threat level. This guide will go over adding custom threat music to a ''new'' region - if you want to replace the threat music in an existing region, the process is largely the same, however it will require an understanding of modification files and their format: [[Downpour Reference/Modification_Files]] To explain the format and its quirks, lets take a look at Chimney Canopy's threat file, <code>cc.txt</code>: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> == Defining Tracks == First, let's focus first on just the top section: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA </syntaxhighlight> Here, the tracks that will be used are defined. First comes the file name of the track (without the extension), such as <code>TH_CC - KICK.ogg</code>, followed by a set of flags. The flags themselves, for example <code>NEUTRAL <PA></code>, are misleading - <u><b>they are unused and do not affect how the track is played in any way</u></b>. For completeness, here are all of the possible flags: <syntaxhighlight> NEUTRAL HIGHKARMA DANGER Any flag may be followed by: <PA> ...which internally sets 'remainInPanicMode', however this field is unused. Likely intended to cause the target track to play for longer after the threat has gone down, but it is unimplemented. </syntaxhighlight> For defining your tracks, you can simply use <code>NEUTRAL</code>. == Defining Layers == To see how to define layers, we can look at the second section: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> Here, layers are defined in increasing level of threat, with minimum threat at the top and maximum threat at the bottom. As the threat increases, more layers are added - there is no practical limit on the number of layers, so you can have as many as you like! Let's take a look at just one layer: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE </syntaxhighlight> Here, we can see this layer has the tracks <code>TH_CC - KICK</code>, <code>TH_CC - PERC1</code>, and <code>TH_CC - NOISE</code>. When a layer has multiple tracks, one is chosen at random to play for that layer. <b></u>Only one track may play for each layer at a time.</b></u> The track that is chosen is only randomly shuffled when there is silence (when there is no threat). Additionally, if a track is already playing due to being chosen in a previous layer, it cannot be chosen by the current layer. Looking at the set of layers again: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> ...we could map out a potential selection of tracks from minimum to maximum threat: <syntaxhighlight> Available: TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE 1. (none) TH_CC - PERC1 is chosen. Available: TH_CC - KICK, TH_CC - PERC2, TH_CC - NOISE 2. (TH_CC - PERC1) TH_CC - NOISE is chosen. Available: TH_CC - KICK, TH_CC - PERC2, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX 3. (TH_CC - PERC1, TH_CC - NOISE) TH_CC - BASS is chosen. Available: KICK, TH_CC - ARPS, TH_CC - SNARE, TH_CC - PERC2, TH_CC - VOX 4. (TH_CC - PERC1, TH_CC - NOISE, TH_CC - BASS) TH_CC - ARPS is chosen. Available: TH_CC - VOX 5. (TH_CC - PERC1, TH_CC - NOISE, TH_CC - BASS, TH_CC - ARPS) TH_CC - VOX is chosen. Final Route: (TH_CC - PERC1, TH_CC - NOISE, TH_CC - BASS, TH_CC - ARPS, TH_CC - VOX) This will only be changed when the music stops. </syntaxhighlight> == Additional Layer Syntax == Some additional syntax exists for restricting when certain tracks within a layer may play: * Prefix an track in a layer with {D} to make it only play during the daytime (redundant/irrelevant if region doesn't use day-night cycles) * Prefix an track in a layer with {N} to make it only play during the nighttime (irrelevant if the region doesn't use day-night cycles) * Prefix an track in a layer with {M} to make it only play while the player is under the influence of mushrooms. * Prefix an track with a subregion name between <code>{}</code> to make it only play in that subregion. Multiple subregions can be specified by separating them with the pipe character (<code>|</code>). For example: <syntaxhighlight> Layer : {D}TH_CC - KICK Layer : {N}TH_CC - PERC2 Layer : {M}TH_CC - SNARE Layer : {Chimney Canopy|The Gutter}TH_CC - ARPS </syntaxhighlight> == Folder Structure == With your <code>xx.txt</code> file complete, you can move onto setting up the necessary folder structure to have your tracks be loaded and played in-game! First, you will need the following file structure under your mod's root directory: <pre>music/procedural</pre> Place your <code>xx.txt</code> within <code>procedural</code>, ensuring <code>xx</code> matches your desired region's acronym. Next, you must add the sound files themselves. There are only 2 conditions: * Sound files must be in <code>.ogg</code> format to be recognized and loaded by the game. * The base name of the sound file (without the extension) must match a track you defined in your <code>xx.txt</code> file. After that, you should be done - warp to your custom region, get into some danger and enjoy your custom threat music in-game! acc41b7e6707872fa2927d78703fb778ce03024e 397 396 2023-03-28T16:30:34Z Forthbridge 91 /* Defining Layers */ wikitext text/x-wiki Threat music utilizes a <code>xx.txt</code> file named after the region it plays in to define both the track layers and the order in which they play depending on the threat level. This guide will go over adding custom threat music to a ''new'' region - if you want to replace the threat music in an existing region, the process is largely the same, however it will require an understanding of modification files and their format: [[Downpour Reference/Modification_Files]] To explain the format and its quirks, lets take a look at Chimney Canopy's threat file, <code>cc.txt</code>: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> == Defining Tracks == First, let's focus first on just the top section: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA </syntaxhighlight> Here, the tracks that will be used are defined. First comes the file name of the track (without the extension), such as <code>TH_CC - KICK.ogg</code>, followed by a set of flags. The flags themselves, for example <code>NEUTRAL <PA></code>, are misleading - <u><b>they are unused and do not affect how the track is played in any way</u></b>. For completeness, here are all of the possible flags: <syntaxhighlight> NEUTRAL HIGHKARMA DANGER Any flag may be followed by: <PA> ...which internally sets 'remainInPanicMode', however this field is unused. Likely intended to cause the target track to play for longer after the threat has gone down, but it is unimplemented. </syntaxhighlight> For defining your tracks, you can simply use <code>NEUTRAL</code>. == Defining Layers == To see how to define layers, we can look at the second section: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> Here, layers are defined in increasing level of threat, with minimum threat at the top and maximum threat at the bottom. As the threat increases, more layers are added - there is no practical limit on the number of layers, so you can have as many as you like! Let's take a look at just one layer: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE </syntaxhighlight> Here, we can see this layer has the tracks <code>TH_CC - KICK</code>, <code>TH_CC - PERC1</code>, and <code>TH_CC - NOISE</code>. When a layer has multiple tracks, one is chosen at random to play for that layer. <b></u>Only one track may play for each layer at a time.</b></u> The track that is chosen is only randomly shuffled when there is silence (when there is no threat). Additionally, if a track is already playing due to being chosen in a previous layer, it cannot be chosen by the current layer. Looking at the set of layers again: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> ...we could map out a potential selection of tracks from minimum to maximum threat: <syntaxhighlight> 1. (none) Available: TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE TH_CC - PERC1 is chosen. 2. (TH_CC - PERC1) Available: TH_CC - KICK, TH_CC - PERC2, TH_CC - NOISE TH_CC - NOISE is chosen. 3. (TH_CC - PERC1, TH_CC - NOISE) Available: TH_CC - KICK, TH_CC - PERC2, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX TH_CC - BASS is chosen. 4. (TH_CC - PERC1, TH_CC - NOISE, TH_CC - BASS) Available: KICK, TH_CC - ARPS, TH_CC - SNARE, TH_CC - PERC2, TH_CC - VOX TH_CC - ARPS is chosen. 5. (TH_CC - PERC1, TH_CC - NOISE, TH_CC - BASS, TH_CC - ARPS) Available: TH_CC - VOX TH_CC - VOX is chosen. Final Route: (TH_CC - PERC1, TH_CC - NOISE, TH_CC - BASS, TH_CC - ARPS, TH_CC - VOX) This will only be changed when the music stops. </syntaxhighlight> == Additional Layer Syntax == Some additional syntax exists for restricting when certain tracks within a layer may play: * Prefix an track in a layer with {D} to make it only play during the daytime (redundant/irrelevant if region doesn't use day-night cycles) * Prefix an track in a layer with {N} to make it only play during the nighttime (irrelevant if the region doesn't use day-night cycles) * Prefix an track in a layer with {M} to make it only play while the player is under the influence of mushrooms. * Prefix an track with a subregion name between <code>{}</code> to make it only play in that subregion. Multiple subregions can be specified by separating them with the pipe character (<code>|</code>). For example: <syntaxhighlight> Layer : {D}TH_CC - KICK Layer : {N}TH_CC - PERC2 Layer : {M}TH_CC - SNARE Layer : {Chimney Canopy|The Gutter}TH_CC - ARPS </syntaxhighlight> == Folder Structure == With your <code>xx.txt</code> file complete, you can move onto setting up the necessary folder structure to have your tracks be loaded and played in-game! First, you will need the following file structure under your mod's root directory: <pre>music/procedural</pre> Place your <code>xx.txt</code> within <code>procedural</code>, ensuring <code>xx</code> matches your desired region's acronym. Next, you must add the sound files themselves. There are only 2 conditions: * Sound files must be in <code>.ogg</code> format to be recognized and loaded by the game. * The base name of the sound file (without the extension) must match a track you defined in your <code>xx.txt</code> file. After that, you should be done - warp to your custom region, get into some danger and enjoy your custom threat music in-game! e71f0bff0f5086ce14a92969356a30411b8203db 398 397 2023-03-28T16:36:09Z Forthbridge 91 /* Defining Layers */ wikitext text/x-wiki Threat music utilizes a <code>xx.txt</code> file named after the region it plays in to define both the track layers and the order in which they play depending on the threat level. This guide will go over adding custom threat music to a ''new'' region - if you want to replace the threat music in an existing region, the process is largely the same, however it will require an understanding of modification files and their format: [[Downpour Reference/Modification_Files]] To explain the format and its quirks, lets take a look at Chimney Canopy's threat file, <code>cc.txt</code>: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> == Defining Tracks == First, let's focus first on just the top section: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA </syntaxhighlight> Here, the tracks that will be used are defined. First comes the file name of the track (without the extension), such as <code>TH_CC - KICK.ogg</code>, followed by a set of flags. The flags themselves, for example <code>NEUTRAL <PA></code>, are misleading - <u><b>they are unused and do not affect how the track is played in any way</u></b>. For completeness, here are all of the possible flags: <syntaxhighlight> NEUTRAL HIGHKARMA DANGER Any flag may be followed by: <PA> ...which internally sets 'remainInPanicMode', however this field is unused. Likely intended to cause the target track to play for longer after the threat has gone down, but it is unimplemented. </syntaxhighlight> For defining your tracks, you can simply use <code>NEUTRAL</code>. == Defining Layers == To see how to define layers, we can look at the second section: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> Here, layers are defined in increasing level of threat, with minimum threat at the top and maximum threat at the bottom. As the threat increases, more layers are added - there is no practical limit on the number of layers, so you can have as many as you like! Let's take a look at just one layer: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE </syntaxhighlight> Here, we can see this layer has the tracks <code>TH_CC - KICK</code>, <code>TH_CC - PERC1</code>, and <code>TH_CC - NOISE</code>. *When a layer has multiple tracks, one is chosen at random to play for that layer. <b></u>Only one track may play for each layer at a time.</b></u> *The track that is chosen is only randomly shuffled when there is silence (when there is no threat). *Additionally, if a track is already playing due to being chosen in a previous layer, it cannot be chosen by the current layer. Looking at the set of layers again: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> ...we could map out a potential selection of tracks from minimum to maximum threat: <syntaxhighlight> 1. (none) Available: TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE TH_CC - PERC1 is chosen. 2. (TH_CC - PERC1) Available: TH_CC - KICK, TH_CC - PERC2, TH_CC - NOISE TH_CC - NOISE is chosen. 3. (TH_CC - PERC1, TH_CC - NOISE) Available: TH_CC - KICK, TH_CC - PERC2, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX TH_CC - BASS is chosen. 4. (TH_CC - PERC1, TH_CC - NOISE, TH_CC - BASS) Available: KICK, TH_CC - ARPS, TH_CC - SNARE, TH_CC - PERC2, TH_CC - VOX TH_CC - ARPS is chosen. 5. (TH_CC - PERC1, TH_CC - NOISE, TH_CC - BASS, TH_CC - ARPS) Available: TH_CC - VOX TH_CC - VOX is chosen. Final Route: (TH_CC - PERC1, TH_CC - NOISE, TH_CC - BASS, TH_CC - ARPS, TH_CC - VOX) This will only be changed when the music stops. </syntaxhighlight> == Additional Layer Syntax == Some additional syntax exists for restricting when certain tracks within a layer may play: * Prefix an track in a layer with {D} to make it only play during the daytime (redundant/irrelevant if region doesn't use day-night cycles) * Prefix an track in a layer with {N} to make it only play during the nighttime (irrelevant if the region doesn't use day-night cycles) * Prefix an track in a layer with {M} to make it only play while the player is under the influence of mushrooms. * Prefix an track with a subregion name between <code>{}</code> to make it only play in that subregion. Multiple subregions can be specified by separating them with the pipe character (<code>|</code>). For example: <syntaxhighlight> Layer : {D}TH_CC - KICK Layer : {N}TH_CC - PERC2 Layer : {M}TH_CC - SNARE Layer : {Chimney Canopy|The Gutter}TH_CC - ARPS </syntaxhighlight> == Folder Structure == With your <code>xx.txt</code> file complete, you can move onto setting up the necessary folder structure to have your tracks be loaded and played in-game! First, you will need the following file structure under your mod's root directory: <pre>music/procedural</pre> Place your <code>xx.txt</code> within <code>procedural</code>, ensuring <code>xx</code> matches your desired region's acronym. Next, you must add the sound files themselves. There are only 2 conditions: * Sound files must be in <code>.ogg</code> format to be recognized and loaded by the game. * The base name of the sound file (without the extension) must match a track you defined in your <code>xx.txt</code> file. After that, you should be done - warp to your custom region, get into some danger and enjoy your custom threat music in-game! 26e758157d476e2304f33c4ed6bd736a24efbcfd 399 398 2023-03-28T16:46:59Z Forthbridge 91 /* Defining Layers */ wikitext text/x-wiki Threat music utilizes a <code>xx.txt</code> file named after the region it plays in to define both the track layers and the order in which they play depending on the threat level. This guide will go over adding custom threat music to a ''new'' region - if you want to replace the threat music in an existing region, the process is largely the same, however it will require an understanding of modification files and their format: [[Downpour Reference/Modification_Files]] To explain the format and its quirks, lets take a look at Chimney Canopy's threat file, <code>cc.txt</code>: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> == Defining Tracks == First, let's focus first on just the top section: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA </syntaxhighlight> Here, the tracks that will be used are defined. First comes the file name of the track (without the extension), such as <code>TH_CC - KICK.ogg</code>, followed by a set of flags. The flags themselves, for example <code>NEUTRAL <PA></code>, are misleading - <u><b>they are unused and do not affect how the track is played in any way</u></b>. For completeness, here are all of the possible flags: <syntaxhighlight> NEUTRAL HIGHKARMA DANGER Any flag may be followed by: <PA> ...which internally sets 'remainInPanicMode', however this field is unused. Likely intended to cause the target track to play for longer after the threat has gone down, but it is unimplemented. </syntaxhighlight> For defining your tracks, you can simply use <code>NEUTRAL</code>. == Defining Layers == To see how to define layers, we can look at the second section: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> Here, layers are defined in increasing level of threat, with minimum threat at the top and maximum threat at the bottom. As the threat increases, more layers are added - there is no practical limit on the number of layers, so you can have as many as you like! Let's take a look at just one layer: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE </syntaxhighlight> Here, we can see this layer has the tracks <code>TH_CC - KICK</code>, <code>TH_CC - PERC1</code>, and <code>TH_CC - NOISE</code>. *When a layer has multiple tracks, one is chosen at random to play for that layer. <b></u>Only one track may play for each layer at a time.</b></u> *The track that is chosen is only randomly shuffled on region change, cycle change, etc. *Additionally, if a track is already playing due to being chosen in a previous layer, it cannot be chosen by the current layer. Looking at the set of layers again: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> ...we could map out a potential selection of tracks from minimum to maximum threat: <syntaxhighlight> 1. (none) Available: TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE TH_CC - PERC1 is chosen. 2. (TH_CC - PERC1) Available: TH_CC - KICK, TH_CC - PERC2, TH_CC - NOISE TH_CC - NOISE is chosen. 3. (TH_CC - PERC1, TH_CC - NOISE) Available: TH_CC - KICK, TH_CC - PERC2, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX TH_CC - BASS is chosen. 4. (TH_CC - PERC1, TH_CC - NOISE, TH_CC - BASS) Available: KICK, TH_CC - ARPS, TH_CC - SNARE, TH_CC - PERC2, TH_CC - VOX TH_CC - ARPS is chosen. 5. (TH_CC - PERC1, TH_CC - NOISE, TH_CC - BASS, TH_CC - ARPS) Available: TH_CC - VOX TH_CC - VOX is chosen. Final Route: (TH_CC - PERC1, TH_CC - NOISE, TH_CC - BASS, TH_CC - ARPS, TH_CC - VOX) This will only be changed when the music stops. </syntaxhighlight> == Additional Layer Syntax == Some additional syntax exists for restricting when certain tracks within a layer may play: * Prefix an track in a layer with {D} to make it only play during the daytime (redundant/irrelevant if region doesn't use day-night cycles) * Prefix an track in a layer with {N} to make it only play during the nighttime (irrelevant if the region doesn't use day-night cycles) * Prefix an track in a layer with {M} to make it only play while the player is under the influence of mushrooms. * Prefix an track with a subregion name between <code>{}</code> to make it only play in that subregion. Multiple subregions can be specified by separating them with the pipe character (<code>|</code>). For example: <syntaxhighlight> Layer : {D}TH_CC - KICK Layer : {N}TH_CC - PERC2 Layer : {M}TH_CC - SNARE Layer : {Chimney Canopy|The Gutter}TH_CC - ARPS </syntaxhighlight> == Folder Structure == With your <code>xx.txt</code> file complete, you can move onto setting up the necessary folder structure to have your tracks be loaded and played in-game! First, you will need the following file structure under your mod's root directory: <pre>music/procedural</pre> Place your <code>xx.txt</code> within <code>procedural</code>, ensuring <code>xx</code> matches your desired region's acronym. Next, you must add the sound files themselves. There are only 2 conditions: * Sound files must be in <code>.ogg</code> format to be recognized and loaded by the game. * The base name of the sound file (without the extension) must match a track you defined in your <code>xx.txt</code> file. After that, you should be done - warp to your custom region, get into some danger and enjoy your custom threat music in-game! e0a15a4bd2e80912a4a4c5e4eed9fc48b842446a 400 399 2023-03-28T16:53:42Z Forthbridge 91 /* Defining Layers */ wikitext text/x-wiki Threat music utilizes a <code>xx.txt</code> file named after the region it plays in to define both the track layers and the order in which they play depending on the threat level. This guide will go over adding custom threat music to a ''new'' region - if you want to replace the threat music in an existing region, the process is largely the same, however it will require an understanding of modification files and their format: [[Downpour Reference/Modification_Files]] To explain the format and its quirks, lets take a look at Chimney Canopy's threat file, <code>cc.txt</code>: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> == Defining Tracks == First, let's focus first on just the top section: <syntaxhighlight> TH_CC - KICK : NEUTRAL <PA> TH_CC - ARPS : NEUTRAL TH_CC - BASS : DANGER <PA> TH_CC - PERC1 : NEUTRAL TH_CC - SNARE : NEUTRAL TH_CC - PERC2 : NEUTRAL <PA> TH_CC - NOISE : DANGER <PA> TH_CC - VOX : HIGHKARMA </syntaxhighlight> Here, the tracks that will be used are defined. First comes the file name of the track (without the extension), such as <code>TH_CC - KICK.ogg</code>, followed by a set of flags. The flags themselves, for example <code>NEUTRAL <PA></code>, are misleading - <u><b>they are unused and do not affect how the track is played in any way</u></b>. For completeness, here are all of the possible flags: <syntaxhighlight> NEUTRAL HIGHKARMA DANGER Any flag may be followed by: <PA> ...which internally sets 'remainInPanicMode', however this field is unused. Likely intended to cause the target track to play for longer after the threat has gone down, but it is unimplemented. </syntaxhighlight> For defining your tracks, you can simply use <code>NEUTRAL</code>. == Defining Layers == To see how to define layers, we can look at the second section: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> Here, layers are defined in increasing level of threat, with minimum threat at the top and maximum threat at the bottom. As the threat increases, more layers are added - there is no practical limit on the number of layers, so you can have as many as you like! Let's take a look at just one layer: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE </syntaxhighlight> Here, we can see this layer has the tracks <code>TH_CC - KICK</code>, <code>TH_CC - PERC1</code>, and <code>TH_CC - NOISE</code>. *When a layer has multiple tracks, one is chosen at random to play for that layer. <b></u>Only one track may play for each layer at a time.</b></u> *The track that is chosen is only randomly shuffled on region change, cycle change, etc. *Additionally, if a track is already playing due to being chosen in a previous layer, it cannot be chosen by the current layer. Looking at the set of layers again: <syntaxhighlight> Layer : TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE Layer : TH_CC - KICK, TH_CC - PERC2, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX Layer : TH_CC - KICK, TH_CC - ARPS, TH_CC - PERC1, TH_CC - NOISE, TH_CC - SNARE, TH_CC - BASS, TH_CC - PERC2, TH_CC - VOX Layer : TH_CC - BASS, TH_CC - VOX </syntaxhighlight> ...we could map out a potential selection of tracks from minimum to maximum threat: <syntaxhighlight> 1. (none) Available: TH_CC - KICK, TH_CC - PERC1, TH_CC - NOISE TH_CC - PERC1 is chosen. 2. (TH_CC - PERC1) Available: TH_CC - KICK, TH_CC - PERC2, TH_CC - NOISE TH_CC - NOISE is chosen. 3. (TH_CC - PERC1, TH_CC - NOISE) Available: TH_CC - KICK, TH_CC - PERC2, TH_CC - SNARE, TH_CC - BASS, TH_CC - VOX TH_CC - BASS is chosen. 4. (TH_CC - PERC1, TH_CC - NOISE, TH_CC - BASS) Available: KICK, TH_CC - ARPS, TH_CC - SNARE, TH_CC - PERC2, TH_CC - VOX TH_CC - ARPS is chosen. 5. (TH_CC - PERC1, TH_CC - NOISE, TH_CC - BASS, TH_CC - ARPS) Available: TH_CC - VOX TH_CC - VOX is chosen. Final Route: (TH_CC - PERC1, TH_CC - NOISE, TH_CC - BASS, TH_CC - ARPS, TH_CC - VOX) This will only be changed on region change, cycle change, etc. </syntaxhighlight> == Additional Layer Syntax == Some additional syntax exists for restricting when certain tracks within a layer may play: * Prefix an track in a layer with {D} to make it only play during the daytime (redundant/irrelevant if region doesn't use day-night cycles) * Prefix an track in a layer with {N} to make it only play during the nighttime (irrelevant if the region doesn't use day-night cycles) * Prefix an track in a layer with {M} to make it only play while the player is under the influence of mushrooms. * Prefix an track with a subregion name between <code>{}</code> to make it only play in that subregion. Multiple subregions can be specified by separating them with the pipe character (<code>|</code>). For example: <syntaxhighlight> Layer : {D}TH_CC - KICK Layer : {N}TH_CC - PERC2 Layer : {M}TH_CC - SNARE Layer : {Chimney Canopy|The Gutter}TH_CC - ARPS </syntaxhighlight> == Folder Structure == With your <code>xx.txt</code> file complete, you can move onto setting up the necessary folder structure to have your tracks be loaded and played in-game! First, you will need the following file structure under your mod's root directory: <pre>music/procedural</pre> Place your <code>xx.txt</code> within <code>procedural</code>, ensuring <code>xx</code> matches your desired region's acronym. Next, you must add the sound files themselves. There are only 2 conditions: * Sound files must be in <code>.ogg</code> format to be recognized and loaded by the game. * The base name of the sound file (without the extension) must match a track you defined in your <code>xx.txt</code> file. After that, you should be done - warp to your custom region, get into some danger and enjoy your custom threat music in-game! cc93e2649dc8ff0cd92a55186b185d44e9b9f68f Downpour Reference/File Formats 0 147 401 353 2023-03-28T17:00:55Z Forthbridge 91 /* Threat Music metadata files */ wikitext text/x-wiki Certain file formats have marginally changed in Downpour with the most common difference being that many things are now stored by value rather than by index. Some files also support new fields / attributes / parameters for new features. Most of these changes are optional and the files will still be parsed properly via backwards compatibility if still stored as indices, but updating may improve mod compatibility for the future. == locks.txt == This is the same, but " : SWAPMAPSYMBOL" can be added to the end of a line to swap the order that the two gate symbols appear on the in-game mini-map. == egates.txt == <code>egates.txt</code> is a new file in the same folder as locks.txt. Placing a gate room name as a new line in this file makes the gate an electric gate. == properties.txt == * Slugcats listed under Broken Shelters should be listed by name rather than index. (<code>Broken Shelters: <u>2</u>: SL_S11''"</code> -&gt; <code>Broken Shelters: <u>Red</u>: SL_S11</code>) * <code>blackSalamanderChance</code> is a new parameter that can be used to change the probability of salamanders in this region spawning as their dark variant. (Default: <code>blackSalamanderChance: 0.33</code>) * <code>corruptionEffectColor</code> is a new parameter than can be used to change the effect color of corruption objects and BLL creatures in the region. (Default <code>corruptionEffectColor: 0.0,0.0,1.0</code>) * <code>corruptionEyeColor</code> is a new parameter than can be used to change the eye color of corruption objects and BLL creatures in the region. (Default <code>corruptionEffectColor: 0.0,0.0,1.0</code>) * <code>kelpColor</code> is a new parameter that can be used to change the color of kelp creatures in the region. * <code>albinos</code> is a new parameter that can make relevant creautres spawn as their albino variants in a region. (Default <code>albinos: false</code>) * <code>waterColorOverride</code> is a new parameter that can change the color that water appears on the in-game minimap for the region. (Default <code>waterColorOverride: 0.05,0.05,0.8</code>) * <code>earlyCycleChance</code> is a new parameter that can set the probability of a pre-cycle event occurring at the start of a cycle in the region. (MSC only) * <code>earlyCycleFloodChance</code> is a new parameter that can set the probability of partial region flooding occuring during a pre-cycle event in this region. (MSC only) * <code>scavsDelayInitialMin</code> is a new parameter that sets the minimum time in ticks before a kill squad will be sent after a disliked player after entering this region. (default 4200) * <code>scavsDelayInitialMax</code> is a new parameter that sets the maximum time in ticks before a kill squad will be sent after a disliked player after entering this region. (default 8200) * <code>scavsDelayRepeatMin</code> is a new parameter that sets the minimum time in ticks before a support squad will be sent to a liked player after entering this region. (default 1100) * <code>scavsDelayRepeatMax</code> is a new parameter that sets the maximum time in ticks before a support squad will be sent to a liked player after entering this region. (default 1700) * Room_Attr lists attractiveness with <code>Neutral,Forbidden,Avoid,Like,Stay</code> instead of <code>0,1,2,3,4</code> respectively -- but it is optional to update this. Properties files can be suffixed by a slugcat name to make a region properties file exclusive to a specific slugcat campaign. (ie: properties-red.txt would apply the properties only while playing as Hunter). == map_xx.txt/map_xx.png == Map files can be suffixed by a slugcat name to make a map render exclusive to a specific slugcat campaign. (ie: <code>map_xx-red.png</code>) == displayname.txt == '''This file is required'''. This file contains a single line that contains the name of the region. This exists in the same folder as the properties / world_xx files. Display name files can also be provided that are suffixed by a slugcat name to change the name of the region for specific slugcat campaigns. (ie: <code>displayname-red.txt</code>) == world_xx.txt == Slugcat-specific spawn lines should be listed by name rather than index. (<code>(<u>0,1</u>)CC_A07 : 3-Mimic-{18}</code> -&gt; <code>(<u>White,Yellow</u>)CC_A07 : 3-Mimic-{18}</code>). Additionally, an "X-" prefix can be added to slugcat-specific spawn filters to invert the filter. For example <code>(<u>X-White,Yellow</u>)CC_A07 : 3-Mimic-{18}</code> would make the spawner appear on any slugcats ''except for'' Survivor and Monk. A new "CONDITIONAL LINKS"/"END CONDITIONAL LINKS" section can be added before the "ROOMS"/"END ROOMS" section in the file to specify room connection changes that apply to specific slugcats. There are three types of conditional link lines: * <code>SLUGCAT : HIDEROOM : ROOM</code> - This excludes the given room from the region when playing as the specified slugcat(s). ** (Example) <code>White,Yellow : HIDEROOM : SU_A99</code> * <code>SLUGCAT : EXCLUSIVEROOM : ROOM</code> - This includes the given room in the region only when playing as the selected slugcat(s). ** (Example) <code>White,Yellow : EXCLUSIVEROOM : SU_A99</code> * <code>SLUGCAT : TARGET_ROOM : TARGET_CONNECTION_ROOM : NEW_CONNECTION_ROOM</code> - This changes the given room connection in the target room to now connect to a different specified room while playing as the specified slugcat(s). For the last conditional link type, the "TARGET_CONNECTION_ROOM" is specified by the room name for named room connections, or with a number to target a DISCONNECTED connection (1 for the first DISCONNECTED pipe in the room, 2 for the second DISCONNECTED, etc). To give an example for this last conditional link line type, imagine the following line existed in the ROOMS/END ROOMS section of the file: <pre>GW_A10 : GW_D01, GW_A07, GW_C06 GW_A11 : GW_B01, GW_D04, DISCONNECTED, GW_F07, DISCONNECTED</pre> Then the following conditional links lines: <pre>White,Yellow : GW_A10 : GW_A07 : DISCONNECTED White,Yellow : GW_A10 : GW_C06 : GW_Z01 White,Yellow : GW_A11 : GW_D04 : GW_H15 White,Yellow : GW_A11 : 1 : GW_K24 White,Yellow : GW_A11 : 2 : GW_X56</pre> Would functionally transform the previous rooms lines to the following when playing as Survivor or Monk: <pre>GW_A10 : GW_D01, DISCONNECTED, GW_Z01 GW_A11 : GW_B01, GW_H15, GW_K24, GW_F07, GW_X56</pre> == room_settings.txt == Room settings files can be suffixed by a slugcat name to make a set of room settings exclusive to a specific slugcat campaign. (ie: <code>su_c03_settings-red.txt</code>) The following entities inside settings files now save by value rather than by index: * Any entities that use slugcat filter lists save the filter list by names rather than a binary flag. Importantly, the names listed are the slugcats who are ''excluded'' from the filter (ie: slugcats who would have had a 0 in the binary string). * Entities with filters include: ** Filter ** Unlock tokens (GoldToken/BlueToken) ** Trigger events (<code>event&lt;tB&gt;</code>) * For these filter lists, when multiple slugcats need to be excluded, their names should be separated by the | character. * <code>DataPearl/UniqueDataPearl</code>: <code>UniqueDataPearl&gt;&lt;2550.05&gt;&lt;2104.999&gt;&lt;37~172~0~0~<u>14</u>~0</code> -&gt; <code>UniqueDataPearl&gt;&lt;2550.05&gt;&lt;2104.999&gt;&lt;37~172~0~0~<u>SL_moon</u>~0</code>. * The type field for <code>StopMusicEvent</code> uses <code>AllSongs/SpecificSong/AllButSpecific</code> instead of <code>0/1/2</code> respectively. == Threat Music metadata files == Main Page: https://rainworldmodding.miraheze.org/wiki/Threat_Music_File_Format * Prefix an instrument in a layer with {D} to make it only play during the daytime (redundant/irrelevant if region doesn't use day-night cycles) * Prefix an instrument in a layer with {N} to make it only play during the nighttime (irrelevant if the region doesn't use day-night cycles) * Prefix an instrument in a layer with {M} to make it only play while the player is under the influence of mushrooms. * Prefix an instrument with a subregion name between <code>{}</code> to make it only play in that subregion. Multiple subregions can be specified by separating them with the pipe character (<code>|</code>). ** Example: <code>{Five Pebbles (Recursive Transform Array)|Five Pebbles (Unfortunate Development)}TH_SS - NOISE''</code> == Short Strings == Each language has its own separate short strings file located at <code>text_xxx/short_strings/strings.txt</code>. Each line of this file is a Key|Value pair. a95d5933460ac7c4e6c6f0b2cada499cc7bd0d89 Getting Started 0 177 403 2023-03-29T01:45:58Z O645 140 Setup a collection of links to make it easier for new modders to find resources. wikitext text/x-wiki {{Cleanup}} === "I'm new to coding" === Rainworld is coded in C#. You will want a good understanding of it, along with understanding how object orientated programming works. For specific resources on learning C#, see [[Learning_C_Sharp|Learning C#]] === "I understand C#, How do i make mods?" === In general, mods are made by 'hooking' into Rainworld's existing methods, and putting your own code either before or after those methods. For getting started with hooking and Bepin plugins, see [[BepInPlugins]]<br> You will need to download either [https://github.com/dnSpy/dnSpy dnSpy] or [https://github.com/icsharpcode/ILSpy ILSpy]. Both decompile the game's code so you can read it. ILspy is better at decompiling than dnSpy, but has a worse interface.<br> You can find Rainworld's code in <code>Rain World\RainWorld_Data\Managed\Assembly-CSharp.dll</code>. Simply open this file up with either program. While a little outdated, [https://www.youtube.com/playlist?list=PLuHyVLkKIJi3P6xu-V3aRTAlwWpdDKxSa Henpe's modding guides] are very useful at explaining how the game works. Video 1 is very outdated however. When starting out, you'll want to use a mod template to setup your plugin. For example, Noir's mod templates: * [https://github.com/NoirCatto/RainWorldRemix/tree/master/Templates/TemplateMod Template without options menu] * [https://github.com/NoirCatto/RainWorldRemix/tree/master/Templates/TemplateModWithOptions Template with options menu] You will need to add dependencies to your file. You can do this by rightclicking 'dependencies' -> Add Project Reference -> Browse -> then find the .dll files in your Rainworld install (or if your depending on a mod, in your Workshop files.) Generally you will want to always depend on <code>Rain World\BepInEx\utils\PUBLIC-Assembly-CSharp.dll</code> and <code>Rain World\BepInEx\plugins\HOOKS-Assembly-CSharp.dll</code>. === "I want to make a custom slugcat!" === Custom slugcats are made easy by using [https://steamcommunity.com/workshop/filedetails/?id=2933196558 Slugbase]. It has it's own set of tutorials and documentation on it's [https://slimecubed.github.io/slugbase/ github page], along with a [https://slimecubed.github.io/slugbase/articles/template.html template] to get started. === "I want to make custom sprites for DMS!" === DMS sprites work very similarly to FancySlugCat sprites. Mehri has made a [https://steamcommunity.com/sharedfiles/filedetails/?id=2902555797 guide] on the steam community explaing how to create them. === "I want to make a custom lizard/variant of any creature!" === Fisobs is used in creating custom creatures. It is made primarily for unique creatures, but can also be used to create variants. [https://github.com/Dual-Iron/fisobs/tree/master/examples Fisob's examples of a custom creature and item] In general, you want to have Fisobs return the creature/ai/state of what you are making a variant of, and then hook into that creature's methods to change it based on if that creature's template.type is your custom variant's template. For those making custom lizards based on lizard customizer, BreedParams is where most of your lizard customizer stats will go. Lizard customizer is also '''NOT compatible''' with Fisobs custom lizards! === "I want to make levels/regions!" === General good advice is to study existing rooms! Your installation of the level editor should come with the project files of all the basegame rooms, you can open these up to study. Look at how the tiles and materials were done, along with the general flow of the level. You can download the Official Level Editor [https://ln5.sync.com/dl/2c28693d0/q2b2zh8m-vdmsuwyj-5w3efg5c-gvhg7ben/view/default/11921401610004 here]. An indepth guide to starting with the level editor can be found at [[Region_From_The_Ground_Up|Region From The Ground Up]] There is also the [https://drive.google.com/drive/folders/1TlriD672VL00PkJlx5jpP-b5E5YwctKn Community Level Editor]. You install it ontop of your official level editor. It will add on community materials and effects, along with making the level editor more stable and including reminders for the keybinds! [https://github.com/timofey260/RWE-Plus Timofey's RWE+] is an alternative level editor. It renders using Drizzle, a custom renderer. RWE+ has a more user friendly interface, and Drizzle is a much faster renderer than the normal renderer. However, you will not be able to use community materials and effects with it. Kaeporo has created a video guide to using the level editor, [https://youtu.be/YQ0DO-fmPCE availiable here]. Solar has collected a repository of community made tiles and props for the leditor, along with the level project files of many modded regions. [https://github.com/solaristheworstcatever/Modded-Regions-Starter-Pack Github Link]. Bro has created a world editor program to make it easier to setup a region's connections, spawns and maps, [https://github.com/Bro748/World-Editor/releases/tag/MSC-1.00 downloadable from github here]. When you want to put your levels in game, you will put your rendered level files (a .txt and .pngs for each camera) in: * <code>mods\[yourmod'sname]\levels</code> for Arena levels. * <code>mods\[yourmod'sname]\world\[regionacronymn]_rooms</code> for region rooms. For regions you will also need a <code>world_[region acronym].txt</code> in \mods\[yourmod'sname]\world\[regionacronymn]<br> For example, a region with the acronymn <code>GM</code> would have a <code>world_GM.txt</code> in <code>\world\GM</code>, and its rooms would be in <code>\world\GM-rooms</code> Once in game, you will likely want to change the palette and add effects and objects in to the room. You can use Dev Tools to do this. First you need to enable it in the remix menu, then once in game you can enable it by pressing <code>O</code>. The main Dev Tools menu is opened by pressing <code>H</code>. For more info on the devtool's menu, see [[Dev_Tools|Dev Tools]]<br> [https://steamcommunity.com/sharedfiles/filedetails/?id=2920439476 Regionkit] is a dependency that contains many useful objects and settings such as custom shelter behaviours, custom decals, animated machinery, particles systems etc. These can be accessed primarily through Dev Tools. 54532293d3f153721ec34f0ca779b7e73091f450 404 403 2023-03-29T14:02:08Z O645 140 Changed formatting a bit to make it slightly more clearer, Split up the level editor section into the main information and additional resources. Fixed spelling mistakes. wikitext text/x-wiki {{Cleanup}} == "I want to make a code mod!" == === "I'm new to coding." === Rainworld is coded in C#. You will want a good understanding of it, along with understanding how object orientated programming works. For specific resources on learning C#, see [[Learning_C_Sharp|Learning C#]] === "I understand C#, How do I make mods?" === In general, mods are made by 'hooking' into Rainworld's existing methods, and putting your own code either before or after those methods. For getting started with hooking and Bepin plugins, see [[BepInPlugins]]<br> You will need to download either [https://github.com/dnSpy/dnSpy dnSpy] or [https://github.com/icsharpcode/ILSpy ILSpy]. Both decompile the game's code so you can read it. ILspy is better at decompiling than dnSpy, but has a worse interface.<br> You can find Rainworld's code in <code>Rain World\RainWorld_Data\Managed\Assembly-CSharp.dll</code>. Simply open this file up with either program. While a little outdated, [https://www.youtube.com/playlist?list=PLuHyVLkKIJi3P6xu-V3aRTAlwWpdDKxSa Henpe's modding guides] are very useful at explaining how the game works. Video 1 is very outdated, however. When starting out, you'll want to use a mod template to setup your plugin. For example, Noir's mod templates: * [https://github.com/NoirCatto/RainWorldRemix/tree/master/Templates/TemplateMod Template without options menu] * [https://github.com/NoirCatto/RainWorldRemix/tree/master/Templates/TemplateModWithOptions Template with options menu] You will need to add dependencies to your file. You can do this by right clicking 'dependencies' -> Add Project Reference -> Browse -> then find the .dll files in your Rainworld install (or if you’re depending on a mod, in your Workshop files.) Generally you will want to always depend on <code>Rain World\BepInEx\utils\PUBLIC-Assembly-CSharp.dll</code> and <code>Rain World\BepInEx\plugins\HOOKS-Assembly-CSharp.dll</code>. === "I want to make a custom slugcat!" === Custom slugcats are made easy by using [https://steamcommunity.com/workshop/filedetails/?id=2933196558 Slugbase]. It has its own set of tutorials and documentation on its [https://slimecubed.github.io/slugbase/ Github page], along with a [https://slimecubed.github.io/slugbase/articles/template.html template] to get started. === "I want to make custom sprites for DMS!" === DMS sprites work very similarly to FancySlugCat sprites. Mehri has made a [https://steamcommunity.com/sharedfiles/filedetails/?id=2902555797 guide] on the steam community explaining how to create them. === "I want to make a custom lizard/variant of any creature!" === Fisobs is used in creating custom creatures. It is made primarily for unique creatures but can also be used to create variants. [https://github.com/Dual-Iron/fisobs/tree/master/examples Fisobs’ examples of a custom creature and item] In general, you want to have Fisobs return the creature/ai/state of what you are making a variant of, and then hook into that creature's methods to change it based on if that creature's template.type is your custom variant's template. For those making custom lizards based on lizard customizer, BreedParams is where most of your lizard customizer stats will go. Lizard customizer is also '''NOT compatible''' with Fisobs custom lizards! == "I want to make levels/regions!" == General good advice is to study existing rooms! Your installation of the level editor should come with the project files of all the base game rooms, you can open these up to study. Look at how the tiles and materials were done, along with the general flow of the level. You can download the Official Level Editor [https://ln5.sync.com/dl/2c28693d0/q2b2zh8m-vdmsuwyj-5w3efg5c-gvhg7ben/view/default/11921401610004 here]. An in depth guide to starting with the level editor can be found at [[Region_From_The_Ground_Up|Region From The Ground Up]] Kaeporo has created a video guide to using the level editor, [https://youtu.be/YQ0DO-fmPCE available here]. When you want to put your levels in game, you will put your rendered level files (a .txt and .pngs for each camera) in: * <code>mods\[yourmod'sname]\levels</code> for Arena levels. * <code>mods\[yourmod'sname]\world\[regionacronymn]_rooms</code> for region rooms. For regions you will also need a <code>world_[region acronym].txt</code> in \mods\[yourmod'sname]\world\[regionacronymn]<br> For example, a region with the acronym <code>GM</code> would have a <code>world_GM.txt</code> in <code>\world\GM</code>, and its rooms would be in <code>\world\GM-rooms</code> Once in game, you will likely want to change the palette and add effects and objects into the room. You can use Dev Tools to do this. First you need to enable it in the remix menu, then once in game you can enable it by pressing <code>O</code>. The main Dev Tools menu is opened by pressing <code>H</code>. For more info on the devtool's menu, see [[Dev_Tools|Dev Tools]] === Additional Resources === There is also the [https://drive.google.com/drive/folders/1TlriD672VL00PkJlx5jpP-b5E5YwctKn Community Level Editor]. You install it on top of your official level editor. It will add on community materials and effects, along with making the level editor more stable and including reminders for the keybinds! [https://github.com/timofey260/RWE-Plus Timofey's RWE+] is an alternative level editor. It renders using Drizzle, a custom renderer. RWE+ has a more user friendly interface, and Drizzle is a much faster renderer than the normal renderer. However, you will not be able to use community materials and effects with it. Solar has collected a repository of community made tiles and props for the Level editor, along with the level project files of many modded regions. [https://github.com/solaristheworstcatever/Modded-Regions-Starter-Pack Github Link]. Bro has created a world editor program to make it easier to setup a region's connections, spawns, and maps, [https://github.com/Bro748/World-Editor/releases/tag/MSC-1.00 downloadable from Github here]. <br> [https://steamcommunity.com/sharedfiles/filedetails/?id=2920439476 Regionkit] is a dependency that contains many useful objects and settings such as custom shelter behaviours, custom decals, animated machinery, particles systems etc. These can be accessed primarily through Dev Tools. 0e14e1f1dc55b81e711b80f08deabf2172f111ea 405 404 2023-03-29T16:23:43Z O645 140 Added LB's Undersea Lizard for download as an example. wikitext text/x-wiki {{Cleanup}} == "I want to make a code mod!" == === "I'm new to coding." === Rainworld is coded in C#. You will want a good understanding of it, along with understanding how object orientated programming works. For specific resources on learning C#, see [[Learning_C_Sharp|Learning C#]] === "I understand C#, How do I make mods?" === In general, mods are made by 'hooking' into Rainworld's existing methods, and putting your own code either before or after those methods. For getting started with hooking and Bepin plugins, see [[BepInPlugins]]<br> You will need to download either [https://github.com/dnSpy/dnSpy dnSpy] or [https://github.com/icsharpcode/ILSpy ILSpy]. Both decompile the game's code so you can read it. ILspy is better at decompiling than dnSpy, but has a worse interface.<br> You can find Rainworld's code in <code>Rain World\RainWorld_Data\Managed\Assembly-CSharp.dll</code>. Simply open this file up with either program. While a little outdated, [https://www.youtube.com/playlist?list=PLuHyVLkKIJi3P6xu-V3aRTAlwWpdDKxSa Henpe's modding guides] are very useful at explaining how the game works. Video 1 is very outdated, however. When starting out, you'll want to use a mod template to setup your plugin. For example, Noir's mod templates: * [https://github.com/NoirCatto/RainWorldRemix/tree/master/Templates/TemplateMod Template without options menu] * [https://github.com/NoirCatto/RainWorldRemix/tree/master/Templates/TemplateModWithOptions Template with options menu] You will need to add dependencies to your file. You can do this by right clicking 'dependencies' -> Add Project Reference -> Browse -> then find the .dll files in your Rainworld install (or if you’re depending on a mod, in your Workshop files.) Generally you will want to always depend on <code>Rain World\BepInEx\utils\PUBLIC-Assembly-CSharp.dll</code> and <code>Rain World\BepInEx\plugins\HOOKS-Assembly-CSharp.dll</code>. === "I want to make a custom slugcat!" === Custom slugcats are made easy by using [https://steamcommunity.com/workshop/filedetails/?id=2933196558 Slugbase]. It has its own set of tutorials and documentation on its [https://slimecubed.github.io/slugbase/ Github page], along with a [https://slimecubed.github.io/slugbase/articles/template.html template] to get started. === "I want to make custom sprites for DMS!" === DMS sprites work very similarly to FancySlugCat sprites. Mehri has made a [https://steamcommunity.com/sharedfiles/filedetails/?id=2902555797 guide] on the steam community explaining how to create them. === "I want to make a custom lizard/variant of any creature!" === Fisobs is used in creating custom creatures. It is made primarily for unique creatures but can also be used to create variants. [https://github.com/Dual-Iron/fisobs/tree/master/examples Fisobs’ examples of a custom creature and item]<br> LB has provided an example of a working Lizard variant to examine, downloadable [https://cdn.discordapp.com/attachments/1083483097145819348/1087296693684408380/Undersea_-_Copy.zip here].<br> In general, you want to have Fisobs return the creature/ai/state of what you are making a variant of, and then hook into that creature's methods to change it based on if that creature's template.type is your custom variant's template. For those making custom lizards based on a lizard customizer lizard, BreedParams is where most of your lizard customizer stats will go. Lizard customizer is also '''NOT compatible''' with Fisobs custom lizards! == "I want to make levels/regions!" == General good advice is to study existing rooms! Your installation of the level editor should come with the project files of all the base game rooms, you can open these up to study. Look at how the tiles and materials were done, along with the general flow of the level. You can download the Official Level Editor [https://ln5.sync.com/dl/2c28693d0/q2b2zh8m-vdmsuwyj-5w3efg5c-gvhg7ben/view/default/11921401610004 here]. An in depth guide to starting with the level editor can be found at [[Region_From_The_Ground_Up|Region From The Ground Up]] Kaeporo has created a video guide to using the level editor, [https://youtu.be/YQ0DO-fmPCE available here]. When you want to put your levels in game, you will put your rendered level files (a .txt and .pngs for each camera) in: * <code>mods\[yourmod'sname]\levels</code> for Arena levels. * <code>mods\[yourmod'sname]\world\[regionacronymn]_rooms</code> for region rooms. For regions you will also need a <code>world_[region acronym].txt</code> in \mods\[yourmod'sname]\world\[regionacronymn]<br> For example, a region with the acronym <code>GM</code> would have a <code>world_GM.txt</code> in <code>\world\GM</code>, and its rooms would be in <code>\world\GM-rooms</code> Once in game, you will likely want to change the palette and add effects and objects into the room. You can use Dev Tools to do this. First you need to enable it in the remix menu, then once in game you can enable it by pressing <code>O</code>. The main Dev Tools menu is opened by pressing <code>H</code>. For more info on the devtool's menu, see [[Dev_Tools|Dev Tools]] === Additional Resources === There is also the [https://drive.google.com/drive/folders/1TlriD672VL00PkJlx5jpP-b5E5YwctKn Community Level Editor]. You install it on top of your official level editor. It will add on community materials and effects, along with making the level editor more stable and including reminders for the keybinds! [https://github.com/timofey260/RWE-Plus Timofey's RWE+] is an alternative level editor. It renders using Drizzle, a custom renderer. RWE+ has a more user friendly interface, and Drizzle is a much faster renderer than the normal renderer. However, you will not be able to use community materials and effects with it. Solar has collected a repository of community made tiles and props for the Level editor, along with the level project files of many modded regions. [https://github.com/solaristheworstcatever/Modded-Regions-Starter-Pack Github Link]. Bro has created a world editor program to make it easier to setup a region's connections, spawns, and maps, [https://github.com/Bro748/World-Editor/releases/tag/MSC-1.00 downloadable from Github here]. <br> [https://steamcommunity.com/sharedfiles/filedetails/?id=2920439476 Regionkit] is a dependency that contains many useful objects and settings such as custom shelter behaviours, custom decals, animated machinery, particles systems etc. These can be accessed primarily through Dev Tools. d19e95d4590cbd5ae2d6c67acb774410cc4fc51a Main Page 0 1 407 331 2023-03-30T20:44:29Z Thalber 3 Change mentions of remix to present tense wikitext text/x-wiki __NOTOC__ [[File:RWModdingTitle.png|800px|frameless|center]] <br> <div id="intro-text" style="text-align: center;"> '''Welcome!''' The Rain World Modding Wiki is a place to share information about modding the video game, ''Rain World''. For more about the game, check out the '''[https://rainworld.miraheze.org/wiki/Rain_World_Wiki Official Rain World Wiki]'''! This wiki is currently in the process of being ported from an old wiki. To get involved, be sure to check out the modding category in the [https://discord.gg/rainworld Rain World Discord]. </div> == Where to Start... == For instructions for installing mods, see [[Installing Mods]]. For description of architecture changes occured with release of Downpour, as well as technical reference for the Remix built-in modloader, see [[Downpour Reference]]. On a technical level, mods can be split into the following families: * [[:Category:Code Mods|Code Mods]] (any mod where the main component is a .dll file) * [[:Category:Content Mods|Content Mods]] (this includes region packs, arenas, etc.). Follow one of the links above to learn more about making these kinds of mods. Sometimes there is overlap. For example a [[Custom Region Support|region pack]] (a type of content mod) may require additional code mods for custom creatures, or a code mod may require additional asset files (though often they are embedded within the dll). If you have questions that the wiki can't yet answer, feel free to ask in the modding category in the [https://discord.gg/rainworld Rain World Discord]. == Contributing == If you have modding knowledge that the wiki doesn't yet have, please do contribute! The following categories contain pages demanding attention: * [[:Category:Cleanup needed]] * [[:Category:Unfinished]] Don't forget to check [[Contribution Guidelines]]. == Quick Links == * [[:Category:Code Mods]] * [[:Category:Content Mods]] * [[:Category:Dev Tools]] * [[:Category:Dependencies]] * [[:Category:Utilities and Tools]] * [[CRS]] * [[Warp]] 47060976fbdf82225b452d2f6e1100372cabcbcd 411 407 2023-03-30T20:57:10Z Thalber 3 Update install page link wikitext text/x-wiki __NOTOC__ [[File:RWModdingTitle.png|800px|frameless|center]] <br> <div id="intro-text" style="text-align: center;"> '''Welcome!''' The Rain World Modding Wiki is a place to share information about modding the video game, ''Rain World''. For more about the game, check out the '''[https://rainworld.miraheze.org/wiki/Rain_World_Wiki Official Rain World Wiki]'''! This wiki is currently in the process of being ported from an old wiki. To get involved, be sure to check out the modding category in the [https://discord.gg/rainworld Rain World Discord]. </div> == Where to Start... == Starting with game version 1.9 (Remix update), mods are installed through Steam Workshop and toggled through in-game Remix menu. If you want to install these mods on a non-Steam copy of the game, see [[Remix Mods Outside of Steam]]. If you want to install mods for a legacy game version (1.5 and below), see [[Legacy Mod Installation]] For description of architecture changes occured with release of Downpour, as well as technical reference for the Remix built-in modloader, see [[Downpour Reference]]. On a technical level, mods can be split into the following families: * [[:Category:Code Mods|Code Mods]] (any mod where the main component is a .dll file) * [[:Category:Content Mods|Content Mods]] (this includes region packs, arenas, etc.). Follow one of the links above to learn more about making these kinds of mods. Sometimes there is overlap. For example a [[Custom Region Support|region pack]] (a type of content mod) may require additional code mods for custom creatures, or a code mod may require additional asset files (though often they are embedded within the dll). If you have questions that the wiki can't yet answer, feel free to ask in the modding category in the [https://discord.gg/rainworld Rain World Discord]. == Contributing == If you have modding knowledge that the wiki doesn't yet have, please do contribute! The following categories contain pages demanding attention: * [[:Category:Cleanup needed]] * [[:Category:Unfinished]] Don't forget to check [[Contribution Guidelines]]. == Quick Links == * [[:Category:Code Mods]] * [[:Category:Content Mods]] * [[:Category:Dev Tools]] * [[:Category:Dependencies]] * [[:Category:Utilities and Tools]] * [[CRS]] * [[Warp]] 4c30593b4fb8afa6569389059f1664527879e1d5 414 411 2023-03-30T21:16:52Z Thalber 3 wikitext text/x-wiki __NOTOC__ [[File:RWModdingTitle.png|800px|frameless|center]] <br> <div id="intro-text" style="text-align: center;"> '''Welcome!''' The Rain World Modding Wiki is a place to share information about modding the video game, ''Rain World''. For more about the game, check out the '''[https://rainworld.miraheze.org/wiki/Rain_World_Wiki Official Rain World Wiki]'''! This wiki is currently in the process of being ported from an old wiki. To get involved, be sure to check out the modding category in the [https://discord.gg/rainworld Rain World Discord]. </div> == Where to Start... == Starting with game version 1.9 (Remix update), mods are installed through Steam Workshop and toggled through in-game Remix menu. If you want to install these mods on a non-Steam copy of the game, see [[Remix Mods Outside of Steam]]. If you want to install mods for a legacy game version (1.5 and below), see [[Legacy Mod Installation]]. For description of architecture changes occured with release of Downpour, as well as technical reference for the Remix built-in modloader, see [[Downpour Reference]]. On a technical level, mods can be split into the following families: * [[:Category:Code Mods|Code Mods]] (any mod where the main component is a .dll file) * [[:Category:Content Mods|Content Mods]] (this includes region packs, arenas, etc.). Follow one of the links above to learn more about making these kinds of mods. Sometimes there is overlap. For example a [[Custom Region Support|region pack]] (a type of content mod) may require additional code mods for custom creatures, or a code mod may require additional asset files (though often they are embedded within the dll). If you have questions that the wiki can't yet answer, feel free to ask in the modding category in the [https://discord.gg/rainworld Rain World Discord]. == Contributing == If you have modding knowledge that the wiki doesn't yet have, please do contribute! The following categories contain pages demanding attention: * [[:Category:Cleanup needed]] * [[:Category:Unfinished]] Don't forget to check [[Contribution Guidelines]]. == Quick Links == * [[:Category:Code Mods]] * [[:Category:Content Mods]] * [[:Category:Dev Tools]] * [[:Category:Dependencies]] * [[:Category:Utilities and Tools]] * [[CRS]] * [[Warp]] 6495e232b4428f76ec60e6881093f687185e0769 Legacy Mod Installation 0 119 408 249 2023-03-30T20:52:53Z Thalber 3 Properly highlight that this page is about legacy version of the game. wikitext text/x-wiki {{Cleanup}} This page contains instructions on how to install and use legacy mods and modloaders '''for old versions of the game (1.5 and below)'''. These versions can be accessed through steam betas menu (game properties, beta, dropdown menu). For installing Remix mods on non-Steam copies of Rain World, see [[Remix Mods outside of Steam]]. Most mods and tools are available on [https://raindb.net/ rainDB] or in <nowiki>#modding-releases</nowiki> channel of [https://discord.gg/rainworld RW Discord server]. When installing a mod, refer to its README file if there is one. You can see what type a mod is by hovering a square icon next to its name on RainDB. == Installing the modloader == === BOI === [[BOI]] is a user-friendly graphical interface for BepInEx. It is not necessary for installing mods, but is useful for people who are not very experienced with computers. To install, follow instructions at [[BOI#Installation]]. Things to note: * Older versions of BOI use a different dialog window for path selection, that one requires you to select the folder game exe is in, not the exe itself. === Bepinex === There are two ways of installing BepInEx: # '''Through BOI''': In the <code>Download Mods / Install BepInEx</code> subwindow, you can press "Install Bepinex". Wait 15 to 20 seconds until the window unfreezes. # '''Manually''' (this is useful if you are not using BOI for some reason): To install, follow instructions at [[BepInEx#Installation]]. === Realm === [[Realm]] is an alternative BepInEx package. It features in-game mod manager menu and some quick reload capabilities. Realm is incompatible with BOI and you should not use the two together. If you plan on using Realm, do not install standard BepInEx. To install, follow instructions at [[Realm#Installation]]. == Installing code mods == === BepInEx + BOI === Mod <code>.dll</code> files go into <code>Rain World/Mods/</code>. You can also drag and drop them into BOI modlist. Use Tags field to set notes for your mods, you can use the search box to filter mods later. Toggle in BOI to enable/disable. To uninstall, uncheck then delete from <code>/Mods/</code>. === Raw BepInEx === [[BepInPlugins]] and [[Partiality|partmods]] go into <code>Rain World/BepInEx/plugins/</code>. [[MonoMod Patches]] go into <code>Rain World/BepInEx/monomod/</code> (they need to be renamed to template <code>AssemblyCSharp.[modname].mm.dll</code>). [[Preloader Patchers]] go into <code>Rain World/BepInEx/patchers/</code>. To uninstall, delete mod .dll file from respective active folder. == Installing region packs == For this, you'll need to have completed [[#Installing the modloader]]. To install custom regions, you will first need [[CRS]] and all of its dependencies. === In-game installer === From CRS Config menu, you can easily install most publicly released region mods in one click from "browse RainDB" tab. You may need to relaunch the game to reload dependency DLLs after everything is done downloading. === Manual === This is useful for installing regpacks that are not publicly available. # Download the regpack archive # Without changing folder structure, unpack it into <code>Rain World/Mods/CustomResources/</code> so that the resulting folders look like the following: <pre> Rain World/ L__ Mods/ L__ CustomResources/ L__ YourRegionMod/ L___ Assets/ L___ World/ L___ Levels/ L___ packInfo.json L___ thumb.png </pre> == Installing standalone mods == [[Standalone Mods]] are installed by folder merging. They usually come as an archive with a folder called <code>Rain World</code> in it. To install a standalone mod, unpack its archive and drag Rain World subfolder from it onto the main game folder, select "replace all files". To uninstall a standalone mod, go to Steam library, right click on Rain World, select Properties -> Local files -> Verify integrity of game files. If you are not on steam, you will probably need to wipe and reinstall your game. == Sprite packs == Sprite packs are asset bundles containing sprite replacements for slugcats. To use them, you need # An asset loader. It can be: #* [[Custom Sprites Loader]] aka CSL (Partmod<!--, instances are additionally bundled with RegionKit-->) #* [[CustomAssets]] (MMPatch) # A character customizer mod. It can be: #* [[FancySlugcats]] (partmod) #* [[ShinyRat]] (Bepinex plugin) Sprite packs usually come with their own READMEs. * When using CustomAssets, the usual way to install a sprite pack is by folder merge. * When using CSL, the sprites can be put into <code>ModConfigs/CustomSpritesLoader/Load/</code> or any subfolder inside it (you need to run the game once with CSL enabled for the folder to be generated). After the sprites have been put into their place, run the game and head into your character customizer's config menu to set sprite names. * When using FancySlugcats, be sure to exactly input sprite names as shown in your sprite pack's README. If you input a name wrong, the game will freeze on start. FancySlugcats is terminally incompatible with some custom character mods. * ShinyRat is crash resistant and more or less works with most character mods. <!--[[Category:End user guides]]--> 3caf129a3e432dec0394aabe362db41664a10909 409 408 2023-03-30T20:53:52Z Thalber 3 Thalber moved page [[Installing Mods]] to [[Legacy Mod Installation]] without leaving a redirect wikitext text/x-wiki {{Cleanup}} This page contains instructions on how to install and use legacy mods and modloaders '''for old versions of the game (1.5 and below)'''. These versions can be accessed through steam betas menu (game properties, beta, dropdown menu). For installing Remix mods on non-Steam copies of Rain World, see [[Remix Mods outside of Steam]]. Most mods and tools are available on [https://raindb.net/ rainDB] or in <nowiki>#modding-releases</nowiki> channel of [https://discord.gg/rainworld RW Discord server]. When installing a mod, refer to its README file if there is one. You can see what type a mod is by hovering a square icon next to its name on RainDB. == Installing the modloader == === BOI === [[BOI]] is a user-friendly graphical interface for BepInEx. It is not necessary for installing mods, but is useful for people who are not very experienced with computers. To install, follow instructions at [[BOI#Installation]]. Things to note: * Older versions of BOI use a different dialog window for path selection, that one requires you to select the folder game exe is in, not the exe itself. === Bepinex === There are two ways of installing BepInEx: # '''Through BOI''': In the <code>Download Mods / Install BepInEx</code> subwindow, you can press "Install Bepinex". Wait 15 to 20 seconds until the window unfreezes. # '''Manually''' (this is useful if you are not using BOI for some reason): To install, follow instructions at [[BepInEx#Installation]]. === Realm === [[Realm]] is an alternative BepInEx package. It features in-game mod manager menu and some quick reload capabilities. Realm is incompatible with BOI and you should not use the two together. If you plan on using Realm, do not install standard BepInEx. To install, follow instructions at [[Realm#Installation]]. == Installing code mods == === BepInEx + BOI === Mod <code>.dll</code> files go into <code>Rain World/Mods/</code>. You can also drag and drop them into BOI modlist. Use Tags field to set notes for your mods, you can use the search box to filter mods later. Toggle in BOI to enable/disable. To uninstall, uncheck then delete from <code>/Mods/</code>. === Raw BepInEx === [[BepInPlugins]] and [[Partiality|partmods]] go into <code>Rain World/BepInEx/plugins/</code>. [[MonoMod Patches]] go into <code>Rain World/BepInEx/monomod/</code> (they need to be renamed to template <code>AssemblyCSharp.[modname].mm.dll</code>). [[Preloader Patchers]] go into <code>Rain World/BepInEx/patchers/</code>. To uninstall, delete mod .dll file from respective active folder. == Installing region packs == For this, you'll need to have completed [[#Installing the modloader]]. To install custom regions, you will first need [[CRS]] and all of its dependencies. === In-game installer === From CRS Config menu, you can easily install most publicly released region mods in one click from "browse RainDB" tab. You may need to relaunch the game to reload dependency DLLs after everything is done downloading. === Manual === This is useful for installing regpacks that are not publicly available. # Download the regpack archive # Without changing folder structure, unpack it into <code>Rain World/Mods/CustomResources/</code> so that the resulting folders look like the following: <pre> Rain World/ L__ Mods/ L__ CustomResources/ L__ YourRegionMod/ L___ Assets/ L___ World/ L___ Levels/ L___ packInfo.json L___ thumb.png </pre> == Installing standalone mods == [[Standalone Mods]] are installed by folder merging. They usually come as an archive with a folder called <code>Rain World</code> in it. To install a standalone mod, unpack its archive and drag Rain World subfolder from it onto the main game folder, select "replace all files". To uninstall a standalone mod, go to Steam library, right click on Rain World, select Properties -> Local files -> Verify integrity of game files. If you are not on steam, you will probably need to wipe and reinstall your game. == Sprite packs == Sprite packs are asset bundles containing sprite replacements for slugcats. To use them, you need # An asset loader. It can be: #* [[Custom Sprites Loader]] aka CSL (Partmod<!--, instances are additionally bundled with RegionKit-->) #* [[CustomAssets]] (MMPatch) # A character customizer mod. It can be: #* [[FancySlugcats]] (partmod) #* [[ShinyRat]] (Bepinex plugin) Sprite packs usually come with their own READMEs. * When using CustomAssets, the usual way to install a sprite pack is by folder merge. * When using CSL, the sprites can be put into <code>ModConfigs/CustomSpritesLoader/Load/</code> or any subfolder inside it (you need to run the game once with CSL enabled for the folder to be generated). After the sprites have been put into their place, run the game and head into your character customizer's config menu to set sprite names. * When using FancySlugcats, be sure to exactly input sprite names as shown in your sprite pack's README. If you input a name wrong, the game will freeze on start. FancySlugcats is terminally incompatible with some custom character mods. * ShinyRat is crash resistant and more or less works with most character mods. <!--[[Category:End user guides]]--> 3caf129a3e432dec0394aabe362db41664a10909 412 409 2023-03-30T20:57:27Z Thalber 3 wikitext text/x-wiki {{Cleanup}} This page contains instructions on how to install and use legacy mods and modloaders '''for old versions of the game (1.5 and below)'''. These versions can be accessed through steam betas menu (game properties, beta, dropdown menu). For installing Remix mods on non-Steam copies of Rain World, see [[Remix Mods Outside of Steam]]. Most mods and tools are available on [https://raindb.net/ rainDB] or in <nowiki>#modding-releases</nowiki> channel of [https://discord.gg/rainworld RW Discord server]. When installing a mod, refer to its README file if there is one. You can see what type a mod is by hovering a square icon next to its name on RainDB. == Installing the modloader == === BOI === [[BOI]] is a user-friendly graphical interface for BepInEx. It is not necessary for installing mods, but is useful for people who are not very experienced with computers. To install, follow instructions at [[BOI#Installation]]. Things to note: * Older versions of BOI use a different dialog window for path selection, that one requires you to select the folder game exe is in, not the exe itself. === Bepinex === There are two ways of installing BepInEx: # '''Through BOI''': In the <code>Download Mods / Install BepInEx</code> subwindow, you can press "Install Bepinex". Wait 15 to 20 seconds until the window unfreezes. # '''Manually''' (this is useful if you are not using BOI for some reason): To install, follow instructions at [[BepInEx#Installation]]. === Realm === [[Realm]] is an alternative BepInEx package. It features in-game mod manager menu and some quick reload capabilities. Realm is incompatible with BOI and you should not use the two together. If you plan on using Realm, do not install standard BepInEx. To install, follow instructions at [[Realm#Installation]]. == Installing code mods == === BepInEx + BOI === Mod <code>.dll</code> files go into <code>Rain World/Mods/</code>. You can also drag and drop them into BOI modlist. Use Tags field to set notes for your mods, you can use the search box to filter mods later. Toggle in BOI to enable/disable. To uninstall, uncheck then delete from <code>/Mods/</code>. === Raw BepInEx === [[BepInPlugins]] and [[Partiality|partmods]] go into <code>Rain World/BepInEx/plugins/</code>. [[MonoMod Patches]] go into <code>Rain World/BepInEx/monomod/</code> (they need to be renamed to template <code>AssemblyCSharp.[modname].mm.dll</code>). [[Preloader Patchers]] go into <code>Rain World/BepInEx/patchers/</code>. To uninstall, delete mod .dll file from respective active folder. == Installing region packs == For this, you'll need to have completed [[#Installing the modloader]]. To install custom regions, you will first need [[CRS]] and all of its dependencies. === In-game installer === From CRS Config menu, you can easily install most publicly released region mods in one click from "browse RainDB" tab. You may need to relaunch the game to reload dependency DLLs after everything is done downloading. === Manual === This is useful for installing regpacks that are not publicly available. # Download the regpack archive # Without changing folder structure, unpack it into <code>Rain World/Mods/CustomResources/</code> so that the resulting folders look like the following: <pre> Rain World/ L__ Mods/ L__ CustomResources/ L__ YourRegionMod/ L___ Assets/ L___ World/ L___ Levels/ L___ packInfo.json L___ thumb.png </pre> == Installing standalone mods == [[Standalone Mods]] are installed by folder merging. They usually come as an archive with a folder called <code>Rain World</code> in it. To install a standalone mod, unpack its archive and drag Rain World subfolder from it onto the main game folder, select "replace all files". To uninstall a standalone mod, go to Steam library, right click on Rain World, select Properties -> Local files -> Verify integrity of game files. If you are not on steam, you will probably need to wipe and reinstall your game. == Sprite packs == Sprite packs are asset bundles containing sprite replacements for slugcats. To use them, you need # An asset loader. It can be: #* [[Custom Sprites Loader]] aka CSL (Partmod<!--, instances are additionally bundled with RegionKit-->) #* [[CustomAssets]] (MMPatch) # A character customizer mod. It can be: #* [[FancySlugcats]] (partmod) #* [[ShinyRat]] (Bepinex plugin) Sprite packs usually come with their own READMEs. * When using CustomAssets, the usual way to install a sprite pack is by folder merge. * When using CSL, the sprites can be put into <code>ModConfigs/CustomSpritesLoader/Load/</code> or any subfolder inside it (you need to run the game once with CSL enabled for the folder to be generated). After the sprites have been put into their place, run the game and head into your character customizer's config menu to set sprite names. * When using FancySlugcats, be sure to exactly input sprite names as shown in your sprite pack's README. If you input a name wrong, the game will freeze on start. FancySlugcats is terminally incompatible with some custom character mods. * ShinyRat is crash resistant and more or less works with most character mods. <!--[[Category:End user guides]]--> 0e1a73485de10bb40f17c01ac205a594238a5cf8 Remix Mods Outside of Steam 0 178 413 2023-03-30T21:14:45Z Thalber 3 init wikitext text/x-wiki {{Cleanup}} Mods are typically distributed through Steam Workshop. However, since the game is also sold on other platforms, some people with a legitimate copy may be unable to access mods normally. We'll ''hope'' you are one of those. == Which mods can I install manually? == To our knowledge, it is against Steam TOS to manually access their API to download workshop items for games you don't have. You have two options: * Some authors provide non-Workshop download links in mod descriptions (usually hosted on GitHub). * If there isn't a direct download link, you can instead ask someone with a Steam copy of the game to download the mod and send you the files. Workshop items are downloaded into subfolders <code>[steamlibrary]/steamapps/workshop/content/312520</code> ('''312520''' is Rain World's steam appid). Subfolders are named by workshop item ID. == How do I install these mods? == [[File:RemixModFolder.png|thumb|Image of correctly placed Remix mod main folder.]] You take the files and put them into <code>[Rain World]/RainWorld_Data/StreamingAssets/mods</code> so that <code>modinfo.json</code> is directly in a subfolder. Exact <code>mods</code> subfolder names do not matter, but it is a good idea to call them something sensible regardless. Done, your mod should appear in Remix menu, be toggleable and work as normal. c1da8907dbd436500793c0b618d7875f825c793e File:RemixModFolder.png 6 179 415 2023-03-30T21:19:58Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:RemixModFolderAndInfoJson.png 6 180 416 2023-03-30T21:30:35Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 Downpour Reference/BepInEx Files 0 148 417 368 2023-03-30T21:31:37Z Thalber 3 yourmodfolder clear up wikitext text/x-wiki DLL files are stored in and loaded directly from the mod folders. This page describes how BepInEx is handled in Downpour. == Directory Structure == [[File:RemixModFolderAndInfoJson.png|thumb|Image of correctly placed Remix mod main folder and a valid modinfo.json file.]] === Toggleable DLLs === The DLL files for your mod will go within a cooresponding location in your mod's folder. DLL files included this way can be toggled on and off using the in-game REMIX menu. DLL files can be called any name, but need to be placed into the following folders to be recognized: * <code>your-mod-folder/plugins/*.dll</code> - Location for any BepInPlugins. * <code>your-mod-folder/patchers/*.dll</code> - Location for any patch mods. Here, "'''your-mod-folder'''" is a subfolder in <code>Rain World/RainWorld_Data/StreamingAssets/mods</code>. Its exact name does not affect the mod loading, but it is a good idea to name it something sensible anyways. Note that Downpour does not attempt to hot-reload DLL mods. If a mod is toggled on or off in the REMIX menu that contains a DLL file, the game will force a relaunch to finish the mod applying process. == Mod Lifecycle Functions == The following lifecycle functions exist in the RainWorld class ('''you need to hook them''') that can be useful for initializing/uninitializing, loading/unloading resources for your mod when it is toggled on and off. {|class="wikitable" ! style="width: 10%" | Method !! style="width: 90%" | Meaning |- | '''OnModsInit()''' || Called when the game is first launched if your mod is one of the enabled mods. Also called any time mods are applied in the REMIX menu if your mod is one of the enabled mods. Because it is called any time the apply button is pressed, expect that this function can be called multiple times in a single game session, so provide checks to ensure you are not double-loading resources if it is called again. |- | '''PreModsInit()''' || Called right before the OnModsInit() function. |- | '''PostModsInit()''' || Called right after the OnModsInit() function. |- | '''OnModsEnabled()''' || Unlike the init function, this is not called when the game is launched. It is called when mods are applied in the REMIX menu, if your mod is now enabled, but ''only'' if it was previously disabled. This is unlike the init function which will be called whenever your mod is enabled even if it was previously enabled as well. This function recieves an argument which contains a list of all newly enabled mods that weren't previously enabled. |- | '''OnModsDisabled()''' || The opposite of the above function. Called when mods are applied in the REMIX menu, if the mod is now disabled, but ''only'' if it was previously enabled. This function recieves an argument which contains a list of all newly disabled mods that were previously enabled. |- | '''PreModsDisabledEnabled()''' || Called before any of the enabled/disabled/init functions are called. Only part of the apply mods workflow; does not get called on game launch. |- | '''PostModsDisabledEnabled()''' || Called after all of the enabled/disabled/init functions are finished being called. Only part of the apply mods workflow; does not get called on game launch. |} == Utility Files == For convenience, the following Assembly-CSharp associated files are automatically generated and available for use: * <code>BepInEx/plugins/HOOKS-Assembly-CSharp.dll</code> - Hookgen for Assembly-CSharp * <code>BepInEx/utils/PUBLIC-Assembly-CSharp.dll</code> - Assembly-CSharp with all members public 73022e6f2481c572efbb5d04000173ac4d43c898 435 417 2023-03-31T14:45:47Z Thalber 3 wikitext text/x-wiki DLL files are stored in and loaded directly from the mod folders. This page describes how BepInEx is handled in Downpour. == Directory Structure == <!--[[File:RemixModFolderAndInfoJson.png|thumb|Image of correctly placed Remix mod main folder and a valid modinfo.json file.]]--> === Toggleable DLLs === The DLL files for your mod will go within a cooresponding location in your mod's folder. DLL files included this way can be toggled on and off using the in-game REMIX menu. DLL files can be called any name, but need to be placed into the following folders to be recognized: * <code>your-mod-folder/plugins/*.dll</code> - Location for any BepInPlugins. * <code>your-mod-folder/patchers/*.dll</code> - Location for any patch mods. Here, "'''your-mod-folder'''" is a subfolder in <code>Rain World/RainWorld_Data/StreamingAssets/mods</code>. Its exact name does not affect the mod loading, but it is a good idea to name it something sensible anyways. Note that Downpour does not attempt to hot-reload DLL mods. If a mod is toggled on or off in the REMIX menu that contains a DLL file, the game will force a relaunch to finish the mod applying process. == Mod Lifecycle Functions == The following lifecycle functions exist in the RainWorld class ('''you need to hook them''') that can be useful for initializing/uninitializing, loading/unloading resources for your mod when it is toggled on and off. {|class="wikitable" ! style="width: 10%" | Method !! style="width: 90%" | Meaning |- | '''OnModsInit()''' || Called when the game is first launched if your mod is one of the enabled mods. Also called any time mods are applied in the REMIX menu if your mod is one of the enabled mods. Because it is called any time the apply button is pressed, expect that this function can be called multiple times in a single game session, so provide checks to ensure you are not double-loading resources if it is called again. |- | '''PreModsInit()''' || Called right before the OnModsInit() function. |- | '''PostModsInit()''' || Called right after the OnModsInit() function. |- | '''OnModsEnabled()''' || Unlike the init function, this is not called when the game is launched. It is called when mods are applied in the REMIX menu, if your mod is now enabled, but ''only'' if it was previously disabled. This is unlike the init function which will be called whenever your mod is enabled even if it was previously enabled as well. This function recieves an argument which contains a list of all newly enabled mods that weren't previously enabled. |- | '''OnModsDisabled()''' || The opposite of the above function. Called when mods are applied in the REMIX menu, if the mod is now disabled, but ''only'' if it was previously enabled. This function recieves an argument which contains a list of all newly disabled mods that were previously enabled. |- | '''PreModsDisabledEnabled()''' || Called before any of the enabled/disabled/init functions are called. Only part of the apply mods workflow; does not get called on game launch. |- | '''PostModsDisabledEnabled()''' || Called after all of the enabled/disabled/init functions are finished being called. Only part of the apply mods workflow; does not get called on game launch. |} == Utility Files == For convenience, the following Assembly-CSharp associated files are automatically generated and available for use: * <code>BepInEx/plugins/HOOKS-Assembly-CSharp.dll</code> - Hookgen for Assembly-CSharp * <code>BepInEx/utils/PUBLIC-Assembly-CSharp.dll</code> - Assembly-CSharp with all members public 02983502d52898912f81f32b7b1d268b800474d7 436 435 2023-03-31T14:47:03Z Thalber 3 wikitext text/x-wiki DLL files are stored in and loaded directly from the mod folders. This page describes how BepInEx is handled in Downpour. == Directory Structure == <!--[[File:RemixModFolderAndInfoJson.png|thumb|Image of correctly placed Remix mod main folder and a valid modinfo.json file.]]--> === Toggleable DLLs === The DLL files for your mod will go within a cooresponding location in your mod's folder. DLL files included this way can be toggled on and off using the in-game REMIX menu. DLL files can be called any name, but need to be placed into the following folders to be recognized: * <code>your-mod-folder/plugins/*.dll</code> - Location for any BepInPlugins. * <code>your-mod-folder/patchers/*.dll</code> - Location for any patch mods. Here, "'''your-mod-folder'''" is a subfolder in <code>Rain World/RainWorld_Data/StreamingAssets/mods</code> (see [[Downpour Reference/Mod Directories]]). Its exact name does not affect the mod loading, but it is a good idea to name it something sensible anyways. Note that Downpour does not attempt to hot-reload DLL mods. If a mod is toggled on or off in the REMIX menu that contains a DLL file, the game will force a relaunch to finish the mod applying process. == Mod Lifecycle Functions == The following lifecycle functions exist in the RainWorld class ('''you need to hook them''') that can be useful for initializing/uninitializing, loading/unloading resources for your mod when it is toggled on and off. {|class="wikitable" ! style="width: 10%" | Method !! style="width: 90%" | Meaning |- | '''OnModsInit()''' || Called when the game is first launched if your mod is one of the enabled mods. Also called any time mods are applied in the REMIX menu if your mod is one of the enabled mods. Because it is called any time the apply button is pressed, expect that this function can be called multiple times in a single game session, so provide checks to ensure you are not double-loading resources if it is called again. |- | '''PreModsInit()''' || Called right before the OnModsInit() function. |- | '''PostModsInit()''' || Called right after the OnModsInit() function. |- | '''OnModsEnabled()''' || Unlike the init function, this is not called when the game is launched. It is called when mods are applied in the REMIX menu, if your mod is now enabled, but ''only'' if it was previously disabled. This is unlike the init function which will be called whenever your mod is enabled even if it was previously enabled as well. This function recieves an argument which contains a list of all newly enabled mods that weren't previously enabled. |- | '''OnModsDisabled()''' || The opposite of the above function. Called when mods are applied in the REMIX menu, if the mod is now disabled, but ''only'' if it was previously enabled. This function recieves an argument which contains a list of all newly disabled mods that were previously enabled. |- | '''PreModsDisabledEnabled()''' || Called before any of the enabled/disabled/init functions are called. Only part of the apply mods workflow; does not get called on game launch. |- | '''PostModsDisabledEnabled()''' || Called after all of the enabled/disabled/init functions are finished being called. Only part of the apply mods workflow; does not get called on game launch. |} == Utility Files == For convenience, the following Assembly-CSharp associated files are automatically generated and available for use: * <code>BepInEx/plugins/HOOKS-Assembly-CSharp.dll</code> - Hookgen for Assembly-CSharp * <code>BepInEx/utils/PUBLIC-Assembly-CSharp.dll</code> - Assembly-CSharp with all members public fcf57a5b8ab916747a71413d34544b8542464abd File:SaintStare.png 6 181 418 2023-03-30T21:55:52Z Thalber 3 wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 419 418 2023-03-30T22:00:54Z Thalber 3 Thalber moved page [[File:saintstare.png]] to [[File:SaintStare.png]] without leaving a redirect wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 Template:Legacy 10 182 420 2023-03-30T22:08:16Z Thalber 3 init wikitext text/x-wiki <includeonly><div class="nomobile">{{Ambox | image = <p><span style="margin-right:15px>[[File:SaintStare.png|47px|middle]]</span> | type = '''Legacy {{{target|article}}}''' | info = This {{{target|article}}} contains information that is only relevant for legacy versions of the game ({{{version|1.5}}} or lower).</p> | border = gray }}</div>[[Category:Legacy]]</includeonly><noinclude> Usage: <nowiki> {{Legacy}} {{Legacy|target=table}} {{Legacy|version=1.01}} (target defaults to "article", version defaults to 1.5) </nowiki> {{Legacy}} {{Legacy|target=table}} {{Legacy|target=section|version=1.01}} </noinclude> 65b3819d5f90654e8a8a5103c1c72b6c829fd912 424 420 2023-03-31T13:37:58Z Thalber 3 switch to badgebase wikitext text/x-wiki <includeonly>{{BadgeBase |icon=SaintStare.png |title=Legacy {{{target|article}}} |body=This {{{target|article}}} contains information that is only relevant for legacy versions of the game ({{{version|1.5}}} or lower) |color=orange }}[[Category:Legacy]]</includeonly><noinclude> Usage: <nowiki> {{Legacy}} {{Legacy|target=table}} {{Legacy|version=1.01}} (target defaults to "article", version defaults to 1.5) </nowiki> {{Legacy}} {{Legacy|target=table}} {{Legacy|target=section|version=1.01}} </noinclude> 5f74e4a592858181530d6b503dd188ec1ea651f4 431 424 2023-03-31T14:03:29Z Thalber 3 wikitext text/x-wiki <includeonly>{{BadgeBase |icon=SaintStare.png |title=Legacy {{{target|article}}} |body=This {{{target|article}}} contains information that is only relevant for legacy versions of the game ({{{version|1.5}}} or lower) |color=green }}[[Category:Legacy]]</includeonly><noinclude> Usage: <nowiki> {{Legacy}} {{Legacy|target=table}} {{Legacy|version=1.01}} (target defaults to "article", version defaults to 1.5) </nowiki> {{Legacy}} {{Legacy|target=table}} {{Legacy|target=section|version=1.01}} </noinclude> 40eecccacdf68f66439555eb979b4345ba32add4 Legacy Mod Installation 0 119 421 412 2023-03-30T22:09:24Z Thalber 3 wikitext text/x-wiki {{Cleanup}} {{Legacy}} This page contains instructions on how to install and use legacy mods and modloaders '''for old versions of the game (1.5 and below)'''. These versions can be accessed through steam betas menu (game properties, beta, dropdown menu). For installing Remix mods on non-Steam copies of Rain World, see [[Remix Mods Outside of Steam]]. Most mods and tools are available on [https://raindb.net/ rainDB] or in <nowiki>#modding-releases</nowiki> channel of [https://discord.gg/rainworld RW Discord server]. When installing a mod, refer to its README file if there is one. You can see what type a mod is by hovering a square icon next to its name on RainDB. == Installing the modloader == === BOI === [[BOI]] is a user-friendly graphical interface for BepInEx. It is not necessary for installing mods, but is useful for people who are not very experienced with computers. To install, follow instructions at [[BOI#Installation]]. Things to note: * Older versions of BOI use a different dialog window for path selection, that one requires you to select the folder game exe is in, not the exe itself. === Bepinex === There are two ways of installing BepInEx: # '''Through BOI''': In the <code>Download Mods / Install BepInEx</code> subwindow, you can press "Install Bepinex". Wait 15 to 20 seconds until the window unfreezes. # '''Manually''' (this is useful if you are not using BOI for some reason): To install, follow instructions at [[BepInEx#Installation]]. === Realm === [[Realm]] is an alternative BepInEx package. It features in-game mod manager menu and some quick reload capabilities. Realm is incompatible with BOI and you should not use the two together. If you plan on using Realm, do not install standard BepInEx. To install, follow instructions at [[Realm#Installation]]. == Installing code mods == === BepInEx + BOI === Mod <code>.dll</code> files go into <code>Rain World/Mods/</code>. You can also drag and drop them into BOI modlist. Use Tags field to set notes for your mods, you can use the search box to filter mods later. Toggle in BOI to enable/disable. To uninstall, uncheck then delete from <code>/Mods/</code>. === Raw BepInEx === [[BepInPlugins]] and [[Partiality|partmods]] go into <code>Rain World/BepInEx/plugins/</code>. [[MonoMod Patches]] go into <code>Rain World/BepInEx/monomod/</code> (they need to be renamed to template <code>AssemblyCSharp.[modname].mm.dll</code>). [[Preloader Patchers]] go into <code>Rain World/BepInEx/patchers/</code>. To uninstall, delete mod .dll file from respective active folder. == Installing region packs == For this, you'll need to have completed [[#Installing the modloader]]. To install custom regions, you will first need [[CRS]] and all of its dependencies. === In-game installer === From CRS Config menu, you can easily install most publicly released region mods in one click from "browse RainDB" tab. You may need to relaunch the game to reload dependency DLLs after everything is done downloading. === Manual === This is useful for installing regpacks that are not publicly available. # Download the regpack archive # Without changing folder structure, unpack it into <code>Rain World/Mods/CustomResources/</code> so that the resulting folders look like the following: <pre> Rain World/ L__ Mods/ L__ CustomResources/ L__ YourRegionMod/ L___ Assets/ L___ World/ L___ Levels/ L___ packInfo.json L___ thumb.png </pre> == Installing standalone mods == [[Standalone Mods]] are installed by folder merging. They usually come as an archive with a folder called <code>Rain World</code> in it. To install a standalone mod, unpack its archive and drag Rain World subfolder from it onto the main game folder, select "replace all files". To uninstall a standalone mod, go to Steam library, right click on Rain World, select Properties -> Local files -> Verify integrity of game files. If you are not on steam, you will probably need to wipe and reinstall your game. == Sprite packs == Sprite packs are asset bundles containing sprite replacements for slugcats. To use them, you need # An asset loader. It can be: #* [[Custom Sprites Loader]] aka CSL (Partmod<!--, instances are additionally bundled with RegionKit-->) #* [[CustomAssets]] (MMPatch) # A character customizer mod. It can be: #* [[FancySlugcats]] (partmod) #* [[ShinyRat]] (Bepinex plugin) Sprite packs usually come with their own READMEs. * When using CustomAssets, the usual way to install a sprite pack is by folder merge. * When using CSL, the sprites can be put into <code>ModConfigs/CustomSpritesLoader/Load/</code> or any subfolder inside it (you need to run the game once with CSL enabled for the folder to be generated). After the sprites have been put into their place, run the game and head into your character customizer's config menu to set sprite names. * When using FancySlugcats, be sure to exactly input sprite names as shown in your sprite pack's README. If you input a name wrong, the game will freeze on start. FancySlugcats is terminally incompatible with some custom character mods. * ShinyRat is crash resistant and more or less works with most character mods. <!--[[Category:End user guides]]--> 258632a0522e9de2de91188ea7793483dc566d3a 430 421 2023-03-31T14:02:04Z Thalber 3 wikitext text/x-wiki {{Legacy}} {{Cleanup}} This page contains instructions on how to install and use legacy mods and modloaders '''for old versions of the game (1.5 and below)'''. These versions can be accessed through steam betas menu (game properties, beta, dropdown menu). For installing Remix mods on non-Steam copies of Rain World, see [[Remix Mods Outside of Steam]]. Most mods and tools are available on [https://raindb.net/ rainDB] or in <nowiki>#modding-releases</nowiki> channel of [https://discord.gg/rainworld RW Discord server]. When installing a mod, refer to its README file if there is one. You can see what type a mod is by hovering a square icon next to its name on RainDB. == Installing the modloader == === BOI === [[BOI]] is a user-friendly graphical interface for BepInEx. It is not necessary for installing mods, but is useful for people who are not very experienced with computers. To install, follow instructions at [[BOI#Installation]]. Things to note: * Older versions of BOI use a different dialog window for path selection, that one requires you to select the folder game exe is in, not the exe itself. === Bepinex === There are two ways of installing BepInEx: # '''Through BOI''': In the <code>Download Mods / Install BepInEx</code> subwindow, you can press "Install Bepinex". Wait 15 to 20 seconds until the window unfreezes. # '''Manually''' (this is useful if you are not using BOI for some reason): To install, follow instructions at [[BepInEx#Installation]]. === Realm === [[Realm]] is an alternative BepInEx package. It features in-game mod manager menu and some quick reload capabilities. Realm is incompatible with BOI and you should not use the two together. If you plan on using Realm, do not install standard BepInEx. To install, follow instructions at [[Realm#Installation]]. == Installing code mods == === BepInEx + BOI === Mod <code>.dll</code> files go into <code>Rain World/Mods/</code>. You can also drag and drop them into BOI modlist. Use Tags field to set notes for your mods, you can use the search box to filter mods later. Toggle in BOI to enable/disable. To uninstall, uncheck then delete from <code>/Mods/</code>. === Raw BepInEx === [[BepInPlugins]] and [[Partiality|partmods]] go into <code>Rain World/BepInEx/plugins/</code>. [[MonoMod Patches]] go into <code>Rain World/BepInEx/monomod/</code> (they need to be renamed to template <code>AssemblyCSharp.[modname].mm.dll</code>). [[Preloader Patchers]] go into <code>Rain World/BepInEx/patchers/</code>. To uninstall, delete mod .dll file from respective active folder. == Installing region packs == For this, you'll need to have completed [[#Installing the modloader]]. To install custom regions, you will first need [[CRS]] and all of its dependencies. === In-game installer === From CRS Config menu, you can easily install most publicly released region mods in one click from "browse RainDB" tab. You may need to relaunch the game to reload dependency DLLs after everything is done downloading. === Manual === This is useful for installing regpacks that are not publicly available. # Download the regpack archive # Without changing folder structure, unpack it into <code>Rain World/Mods/CustomResources/</code> so that the resulting folders look like the following: <pre> Rain World/ L__ Mods/ L__ CustomResources/ L__ YourRegionMod/ L___ Assets/ L___ World/ L___ Levels/ L___ packInfo.json L___ thumb.png </pre> == Installing standalone mods == [[Standalone Mods]] are installed by folder merging. They usually come as an archive with a folder called <code>Rain World</code> in it. To install a standalone mod, unpack its archive and drag Rain World subfolder from it onto the main game folder, select "replace all files". To uninstall a standalone mod, go to Steam library, right click on Rain World, select Properties -> Local files -> Verify integrity of game files. If you are not on steam, you will probably need to wipe and reinstall your game. == Sprite packs == Sprite packs are asset bundles containing sprite replacements for slugcats. To use them, you need # An asset loader. It can be: #* [[Custom Sprites Loader]] aka CSL (Partmod<!--, instances are additionally bundled with RegionKit-->) #* [[CustomAssets]] (MMPatch) # A character customizer mod. It can be: #* [[FancySlugcats]] (partmod) #* [[ShinyRat]] (Bepinex plugin) Sprite packs usually come with their own READMEs. * When using CustomAssets, the usual way to install a sprite pack is by folder merge. * When using CSL, the sprites can be put into <code>ModConfigs/CustomSpritesLoader/Load/</code> or any subfolder inside it (you need to run the game once with CSL enabled for the folder to be generated). After the sprites have been put into their place, run the game and head into your character customizer's config menu to set sprite names. * When using FancySlugcats, be sure to exactly input sprite names as shown in your sprite pack's README. If you input a name wrong, the game will freeze on start. FancySlugcats is terminally incompatible with some custom character mods. * ShinyRat is crash resistant and more or less works with most character mods. <!--[[Category:End user guides]]--> 918fd4578b70b81743923be681e3186a86b86b1a Template:BadgeBase 10 183 422 2023-03-31T13:34:54Z Thalber 3 init wikitext text/x-wiki <includeonly><div class="nomobile">{{Ambox | image = <p><span style="margin-right:15px>[[File:{{{icon|sloogo.png}}}|47px|middle]]</span> | type = '''{{{title|Badge title here}}}''' | info = {{{body|Badge body here.}}}</p> | border = {{{color|gray}}} }}</div>[[Category:Legacy]]</includeonly><noinclude> <nowiki> {{BadgeBase}} {{BadgeBase|title=You can change title of the badge|body=And its body text too}} {{BadgeBase|color=red|title=Recolored badge}} </nowiki> {{BadgeBase}} {{BadgeBase|title=You can change title of the badge|body=And its body text too}} {{BadgeBase|color=red|title=A very red badge|body=Hunter body here|icon=hunterAngy.png}} </noinclude> 23cd7ad906386b042bd21ea4cadaef99fb0d3e31 423 422 2023-03-31T13:35:36Z Thalber 3 wikitext text/x-wiki <includeonly><div class="nomobile">{{Ambox | image = <p><span style="margin-right:15px>[[File:{{{icon|sloogo.png}}}|47px|middle]]</span> | type = '''{{{title|Badge title here}}}''' | info = {{{body|Badge body here.}}}</p> | border = {{{color|gray}}} }}</div></includeonly><noinclude> <nowiki> {{BadgeBase}} {{BadgeBase|title=You can change title of the badge|body=And its body text too}} {{BadgeBase|color=red|title=Recolored badge}} </nowiki> {{BadgeBase}} {{BadgeBase|title=You can change title of the badge|body=And its body text too}} {{BadgeBase|color=red|title=A very red badge|body=Hunter body here|icon=hunterAngy.png}} </noinclude> b883d5d165e30efd283717e7f4ff190caeb34918 Template:Cleanup 10 88 425 294 2023-03-31T13:48:12Z Thalber 3 switch to badgebase wikitext text/x-wiki <includeonly>{{BadgeBase |icon=Hardhatcat.png |title=Cleanup needed |body=This article needs structural or tonal clean-up to meet quality standards. Feel free to help {{fullurl|{{FULLPAGENAME}}|action=edit{{#if: {{{1|}}} | &section={{{1}}} }}|text=improve}} it. }}</includeonly>[[Category:Cleanup needed]]<noinclude> Usage: <nowiki>{{Cleanup}}</nowiki> {{Cleanup}} </noinclude> 10f90a7d1d9ca9e432718eebdf4a26a2dbb498c5 Template:todo 10 120 426 301 2023-03-31T13:51:28Z Thalber 3 switch to badgebase wikitext text/x-wiki <includeonly>{{BadgeBase |icon=monkPower.png |title=This {{{target|section}}} is unfinished |body=This {{{target|section}}} is lacking some / all of critical information. |color=orange}}[[Category:Unfinished]]</includeonly><noinclude> Usage: <nowiki> {{todo}} {{todo|target=table}} (target defaults to "section") </nowiki> {{todo}} {{todo|target=table}} </noinclude> cdcfb0f32332f3f7a8088664d99162e169b9745e BOI 0 110 427 299 2023-03-31T13:56:15Z Thalber 3 add legacy tag wikitext text/x-wiki {{Legacy}} {{Toolinfo |type=Mod manager |authors=thalber |maintainers=thalber |status=LTS |license=The Unlicense |releases=[https://github.com/Rain-World-Modding/BOI GitHub] }} '''BOI''' ''(an abbreviation of a horrendous pun)'' is an external mod manager for [[BepInEx]] initially created with the intent of making migration from [[Partiality]] easier. Glued together in Windows Forms and erratically maintained by a terminally clueless specimen since late 2020, it is a tall tower of bodges that somehow still stands. A hatchling-friendly tutorial to using it can be found [https://youtu.be/brDN_8uN6-U on YouTube]. == Features == === GUI wrapper === BOI has a somewhat straightforward UI for loading/enabling/disabling mods of most common kinds. It imitates the folder behaviour of [[Partiality]] (everything is stored in <code>Rain World/Mods/</code> before being moved to BepInEx active dirs) and attempts to automate some actions counterintuitive to the end user (like renaming assembly files for [[MonoModPatches]]). === Auto-installer === BOI can quickly install a latest valid [[BepInEx]] package and some of the more commonly used mods from [[AUDB]]. === Misc === * Detecting potentially faulty mods * Save state backups * Mod tags and bulk toggling * Post-PL folder cleanup * GUI wrappers for some mod configs == Installation == # Download latest release and unpack the archive. #* It is recommended to keep BOI in a separate folder. #* Make sure that all of archive contents are next to BOI.exe # Run BOI.exe. Press <code>Select path to game</code> ## Navigate to the game's .exe file ## Open it ## Press the same button again == Usage == {{todo}} [[Category:RW-Specific Tools]] a23d69be2eedc5a3afe00c77dc1a1b1b94035f54 ConfigMachine 0 115 428 357 2023-03-31T13:59:55Z Thalber 3 add legacy tag wikitext text/x-wiki {{Legacy}} '''Configmachine''' is a dependency mod that allows other mods to easily create in-game config GUI. It's currently shipped with [[BepInEx]] installation. For Remix config screen, see [[MixedOI]]. == Features == === OptionInterface === This is the most common method of adding config screen to your mod. ==== Registering ==== '''OptionalUI.OptionInterface''' is the base class for option interfaces. <syntaxhighlight lang="csharp"> public class MyOI : OptionInterface { public MyOI() : base (plugin: MyPlugin.instance) // Your BaseUnityPlugin instance. Examples assume you have a static singleton instance of your mod. { } } </syntaxhighlight> Now add <code>LoadOI</code> static method in your <code>BaseUnityPlugin</code> class that returns your OptionInterface. <syntaxhighlight lang="c#"> public static OptionInterface LoadOI() => new MyOI(); //set return type to "object" if you want your mod to be loaded even if CM is not. In that case, you will need to handle CM's absence on your own. </syntaxhighlight> ==== Designing GUI ==== For designing your GUI, using [https://inkscape.org/ Inkscape] is strongly suggested. With Inkscape, create a file with 600 x 600 pixel resolution, then enable [View] - [Canvas Orientation] - [Flip Vertically]. (Alternatively, you can use any CAD program which has up and right as positive axis by default) <!--The image below is a diagram of <code>Colorfoot</code>’s first <code>OpTab</code>.--> [[File:Colorfoot-GUI.png|thumb|right|alt=Colorfoot's GUI as an example|Colorfoot's GUI as an example]] All UIelements have bottom-left <code>pos</code>ition and rectangular <code>size</code>. (Some have <code>fixedSize</code> which you can see from the summary of their constructors). Think every element like rectangles, and arrange them as you need. (Circular UIelements have <code>rad</code> instead; You can consider them as a square with 2 * rad for its dimensions) [[File:Colorfoot-GUI0.png|thumb|none|alt=Example GUI Positioning|Example GUI Positioning]] For <code>pos</code> parameters, use the relative coordinate from bottom-left from the canvas to your item. For <code>size</code> parameters, use their size in pixel. If you’re using Inkscape with [Flip Vertically] setting on, you can get those from their properties without any calculation. [[File:Colorfoot-Inkscape.png|thumb|none|alt=Example GUI Inkscape|Example GUI in Inkscape]] Here are some tips for designing GUI: * If you have many things to display, organise them with categories and use <code>OpRect</code> to surround them. * You don’t have to put everything in a single <code>OpTab</code>. If the canvas gets crowded, disperse your items for easier readability. * Try to avoid using smaller <code>OpScrollBox</code>s to store many things in one place even if that’s an option: The users cannot see everything in a single screen which reduces usability greatly. ==== Initialization ==== <code>OptionInterface.Initialize</code> is called in IntroRoll(for loading configuration) and ConfigMenu (for displaying to users). You can check whether Initialize is called in ConfigMenu or not with <code>OptionInterface.isOptionMenu</code>. It usually goes like this following example: <syntaxhighlight lang="csharp"> public override void Initialize() { base.Initialize(); // This should be called before everything else Tabs = new OpTab[2]; // you can have up to 20 tabs Tabs[0] = new OpTab("Main"); // Each OpTab is 600 x 600 pixel sized canvas Tabs[1] = new OpTab("Second") { color = Color.cyan }; // You can change its button and canvas colour too // After Initializing Tabs, create UIelements and add them to tabs } </syntaxhighlight> Now initialize <code>UIelement</code>s and add them to <code>OpTab</code> (or <code>OpScrollBox</code>). The Z-order (the order in which they’re drawn) of <code>UIelement</code>s is the order of constructors, ''not'' the order they’re added to <code>OpTab</code>. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpLabel(100f, 500f, "My Text") { description = "This is My Text" }); // Any UIelement can have description, which will be shown // at the bottom of the screen when the mouse cursor is over it </syntaxhighlight> <code>UIconfig</code>s are a subcategory of <code>UIelement</code> which have <code>key</code> and <code>value</code> for storing user input values, both of them get saved automatically by Config Machine. Their constructor accepts <code>key</code> and <code>defaultValue</code> on top of everything else. <code>key</code> must be unique for all elements in your OI unless they are cosmetic. Setting the key to empty or anything that starts with <code>_</code> (underbar) will turn it <code>cosmetic</code>, and the value won’t be saved. Cosmetic UIconfig is useful when you want to have provided <code>UIconfig</code> for UI purpose but not for an actual configurable. (Similarly, ModID that starts with <code>_</code> will be completely ignored by Config Machine) <syntaxhighlight lang="csharp"> OpCheckBox chkExample = new OpCheckBox(260f, 360f, "Example", true); Tabs[0].AddItems(chkExample, new OpLabel(260f, 390f, "Enable Example") { bumpBehav = chkExample.bumpBehav }); // BumpBehaviour is Config Machine's custom class that allows smoothly animated reaction with the input // Setting OpLabel's bumpBehav to other UIconfig/UItrigger's bumpBehav allows it to highlight with that element </syntaxhighlight> <code>UItrigger</code>s are the other subcategory of <code>UIelement</code>s which have <code>signal</code>s. When the user activates an <code>UItrigger</code> in some way, it will call the <code>Signal</code> function in OptionInterface which will be explained later. <syntaxhighlight lang="csharp"> Tabs[0].AddItems(new OpSimpleButton(new Vector2(400f, 200f), new Vector2(100f, 24f), "press", "Press Me")); </syntaxhighlight> ==== Update ==== <code>Update</code> function is called every frame when the game is in ConfigMenu, and this OptionInterface is currently active (The user has currently selected this mod from the list on left). This is useful to make reactive GUI, especially since each <code>UIconfig</code> instance can have only one value saved. The following example code uses cosmetic <code>OpRadioButtonGroup</code> to have four <code>OpColorPicker</code>s in a single spot. <syntaxhighlight lang="csharp"> private OpRadioButtonGroup rbgSelect; private int select; private OpColorPicker[] cpkPlayers; public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; select = 0; rbgSelect = new OpRadioButtonGroup("_", select); Tabs[0].AddItems(rbgSelect); rbgSelect.SetButtons(new OpRadioButton[] { new OpRadioButton(50f, 100f){ description = "The Survivor"}, new OpRadioButton(100f, 100f){ description = "The Monk"}, new OpRadioButton(150f, 100f){ description = "The Hunter"}, new OpRadioButton(200f, 100f){ description = "The Nightcat"} } ); OpColorPicker[] cpkPlayers = new OpColorPicker[4]; for (int i = 0; i < 4; i++) { Tabs[0].AddItems(new OpLabel(50f * i, 70f, rbgSelect.buttons[i].description) { bumpBehav = rbgSelect.buttons[i].bumpBehav }); cpkPlayers[i] = new OpColorPicker(new Vector2(100f, 300f), $"Color{i}", "FFFFFF"); cpkPlayers[i].Hide(); } cpkPlayers[select].Show(); Tabs[0].AddItems(cpkPlayers); } public override void Update(float dt) { base.Update(dt); // dt is deltaTime if (select != rbgSelect.valueInt) { for (int i = 0; i < cpkPlayers.Length; i++) { cpkPlayers[i].Hide(); } select = rbgSelect.valueInt; cpkPlayers[select].Show(); } } </syntaxhighlight> ==== ConfigOnChange ==== <code>ConfigOnChange</code> is called whenever <code>config</code> Dictionary is updated, mainly when Config Machine loads OptionInterfaces in IntroRoll, and when the user saves changes of configuration in ConfigMenu. Override this method to grab your configurable values. <code>config</code> Dictionary is where <code>UIconfig</code>’s value is stored. The following is an example of how to convert a string value to the corresponding type. <syntaxhighlight lang="csharp">public override void ConfigOnChange() { base.ConfigOnChange(); MyMod.config.myInt = int.Parse(config["keyInt"]); MyMod.config.myFloat = float.Parse(config["keyFloat"]); MyMod.config.myKey = OpKeyBinder.StringToKeyCode(config["keyKey"]); MyMod.config.myColor = OpColorPicker.HexToColor(config["keyColor"]); } </syntaxhighlight> ==== Signal ==== <code>Signal</code> is called when the user has interacted with <code>UItrigger</code>. Override this to have your OI to react. <syntaxhighlight lang="csharp"> public override void Signal(UItrigger trigger, string signal) { switch (signal) { case "reset": ConfigMenu.ResetCurrentConfig(); // This is the same as pressing Reset Config Button. break; } } </syntaxhighlight> === Generated OIs === <code>GeneratedOI</code> is a child class of <code>OptionInterface</code> that helps generating fixed-format GUI with less effort. <span id="displaying-basic-profile"></span> ==== Displaying Basic Profile ==== Simply inheriting <code>GeneratedOI</code> instead of <code>OptionInterface</code> works. This does make your mod dependent to Config Machine, and Config Machine generates GUI to display the basic information of your mod without this dependency. So this is only useful when you’re using OptionInterface for other features, like its Translation API. <syntaxhighlight lang="c#"> public class MyOI : GeneratedOI { private const string desc = "Changes this thing and that thing"; public MyOI() : base(plugin: MyPlugin.instance, desc) { transFile = "MyPlugin.Translation.txt"; } } </syntaxhighlight> The code above would generate a GUI like the following image: [[File:GeneratedOI-sample.png|thumb|none|alt=GeneratedOI Sample|GeneratedOI Sample]] You can also use its static method <code>AddBasicProfile</code> for basic profiles on top of the canvas. This also has an overload that accepts <code>OpScrollBox</code> instead of <code>OpTab</code>, if you have <code>OpScrollBox</code> replacing <code>OpTab</code>. <syntaxhighlight lang="c#"> public override void Initialize() { base.Initialize(); Tabs = new OpTab[] { new OpTab() }; GeneratedOI.AddBasicProfile(Tabs[0], rwMod); Tabs[0].AddItems(new OpCheckBox(100f, 350f, "EnableStuff", false) { description = "Enables this stuff" }); } </syntaxhighlight> ==== BepInEx.Configuration ==== If you don't provide an OptionInterface, BepInEx can generate a simple config screen from your [[BepInPlugins|plugin]]'s config bindings (see <code>BepInEx.Configuration</code>). If this happens, CM will not create a separate file to store your config values. This method has upsides and downsides. * You don’t need to reference Config Machine in your project, and this doesn’t create a dependency for Config Machine. * The users can configure the plugin by opening the cfg file in Notepad outside the game. * However, you do not have control on detailed GUI design. First, we need <code>ConfigEntry</code> which you can bind to the <code>Config</code> property of <code>BaseUnityPlugin</code>. Consult [https://docs.bepinex.dev/articles/dev_guide/plugin_tutorial/4_configuration.html BepInEx Documentation] for farther detail. <syntaxhighlight lang="c#"> public static ConfigEntry<string> cfgText; public static ConfigEntry<bool> cfgCheck; void Awake() { cfgText = Config.Bind( "General", // section: defines which OpTab this will go "My Setting", // key: the name of setting "Hello, world!" // defaultValue "This is a description. It does things." // The description will be shown the right side of UIconfig // When you hover your mouse on UIconfig, // the first sentence will be displayed at the bottom of the screen ); cfgCheck = Config.Bind("General", "My Other Setting", true, "Another description is this."); } </syntaxhighlight> To access those settings, use <code>Value</code>. <syntaxhighlight lang="c#"> if (cfgCheck.Value) { Logger.LogMessage(cfgText.Value); } </syntaxhighlight> === Translation Support === While you can support translation for your mod on your own, Config Machine also offers translation solution. ==== Preparation ==== <code>OptionInterface</code> has a method called <code>Translate</code>, and when it's initially called, it will load specified (<code>transFile</code>) txt file from your assembly and make Dictionary depending on Rain World's language setting. In <code>BaseUnityPlugin.LoadOI</code> method, store the <code>OptionInterface</code> instance in somewhere before returning it. <syntaxhighlight lang="c#"> public static MyOI oi; public static MyOI LoadOI() { oi = new MyOI(); return oi; } </syntaxhighlight> Then make a static method that calls the translation method. <syntaxhighlight lang="c#">public static string Translate(string orig) { if (oi != null) { return oi.Translate(orig); } return orig; } </syntaxhighlight> Now when you need to translate something, you can pass your string through this method. ==== Writing Translation txt ==== Create a txt file that contains translation, too. Add txt file to your project, ''make sure'' that its encoding is <code>UTF-8</code>, then set it to be [Embedded Resources] for its compile setting. Then, in the constructor of your OptionInterface, set <code>transFile</code> to that resource name. If you have not put it in any folder, it's usually <code>&lt;ProjectName&gt;.&lt;TxtFileName&gt;.txt</code>, but you might get it wrong. If it's wrong when <code>OptionInterface.Translate</code> is initially called, Config Machine will log all the resources in your assembly in exceptionLog.txt so you can copy from it. <syntaxhighlight lang="c#"> public MyOI() : base(plugin: MyPlugin.instance) { this.transFile = "MyPlugin.Translation.txt"; // if you do not know the resource name, just call Translate. // ConfigMachine will log all the resources in your assembly in exceptionLog.txt. } </syntaxhighlight> The format of the translation txt file for Config Machine is quite primitive. First, you add a keyword, then <code>|</code> for language separator, then language ID (<code>eng, ita, ger, spa, por, kor, jap, rus)</code>), <code>$</code> for another separator, then translation. If there is no translation, the translator will return the keyword, unless there is a translation for <code>eng</code>. (In that case, English "translation" will be used as default translation) The following is formatting example for txt file. <!-- corrupted korean samples have been replaced with russian, sorry folks ~~thalber --> <pre> // If the first two characters are '//', this line will be ignored. Nightcat Horn Colour|rus$Цвет рога // If you have variables, avoid using partial sentences. Not every language has the same subject-verb-object order. Press &lt;ThrowKey&gt; to stab.|rus$Нажмите &lt;ThrowKey&gt; для атаки. // When translating the shorter-phrase, the translation might be sensitive with context, but English one does not. Duplicate key causes error(You can check exceptionLog.txt for duplicates), so you can set 'eng' translation for these cases. Property_as of possession|eng$Property|rus$Собственность Property_as of quality|eng$Property|rus$Свойство // For line-breaks, use \n. (In code, it'd be \\n) Each line represents a phrase, so you can't use actual line-break in a single chunk. LINE\nBREAK|rus$ПЕРЕНОС\nСТРОКИ</pre> ==== Running Translation ==== And here are some examples in code. Yes, running every text through the <code>Translate</code> method is tedious, but this is usually how it's done in Rain World or many other games. Make sure to check your mod in another language to confirm you haven’t missed any item. <syntaxhighlight lang="c#"> labelCpkrRadio.text = MyPlugin.Translate("Nightcat Horn Colour"); instance.room.game.cameras[0].hud.textPrompt.AddMessage(MyPlugin.Translate("Press <ThrowKey> to stab.").Replace("<ThrowKey>", k.ToString())); // k is variable in this example. labelLineBreak.text = MyPlugin.Translate("LINE\\nBREAK"); </syntaxhighlight> <!-- These aren't the part of tutorial but more of tips. This does not just apply for making Rain World mods but to general, whenever you're making something that supports translation. * When you have variables in your sentence, do not use partial phrases and Frankenstein it later with <code>string.Concat</code>. Not every language has the same grammar order of subject-verb-object as English. * Leave credits to the translators, since you¡¯re most likely getting volunteers from them. This is both good for showing gratitude to the translators and keeping the quality of the translation. The lack of credits equals a lack of responsibility. * Do not use machine translation. That usually hurts the user experience rather than enhancing it. --> == Acceptable Types == As of Config Machine <code>v1.5.1</code>, it accepts the following types and uses provided UIconfig. (Height is the pixel height that how much this ConfigEntry would use. And each entry get 20 pixeled gaps in between) {|class="wikitable" !align="right" width="23%"| type !align="center" width="29%"| UIconfig !align="right" width="23%"| Height !width="23%"| Note |- |align="right"| bool |align="center"| OpCheckBox |align="right"| 60 | |- |align="right"| byte |align="center"| OpSliderSubtle |align="right"| 90 | Range: [0, 20] |- |align="right"| uint |align="center"| OpSlider |align="right"| 90 | Range: [0, 100] |- |align="right"| int |align="center"| OpTextBox |align="right"| 60 | Accepts: Int |- |align="right"| float |align="center"| OpTextBox |align="right"| 60 | Accepts: Float |- |align="right"| string(Hex) |align="center"| OpColorPicker |align="right"| 170 | When defaultValue is Hex |- |align="right"| string |align="center"| OpTextBox |align="right"| 60 | When defaultValue is not Hex; Accepts: ASCII |- |align="right"| KeyCode |align="center"| OpKeyBinder |align="right"| 100 | |- |align="right"| enumType |align="center"| OpResourceSelector |align="right"| 60 | |- |align="right"| default |align="center"| N/A |align="right"| | Will warn the user that this plugin has ConfigEntry that’s not supported by Config Machine |} == Available UI Elements == Full list of available UI elements can be found [[ConfigMachine/Provided Elements|here]]. [[Category:Dependencies]] [[Category:Code Mods]] 1d3a6b98d270edee7a55497f4d864c296b11b935 ConfigMachine/Provided Elements 0 118 429 190 2023-03-31T14:00:34Z Thalber 3 add legacy tag wikitext text/x-wiki {{Legacy}} {{Cleanup}} This page is '''unfinished''' and needs to be expanded. This page contains a list of UIElements provided by default with [[ConfigMachine]]. Up to date with Config Machine <code>v1.5.1</code>. This page explains what each provided <code>UIelement</code> is and how to use them. You can check out the source code of Config Machine from its [https://github.com/metnias/CompletelyOptional github page], or have <code>ConfigMachine.xml</code> in your Reference folder for summaries. However, there are functions left unused (mainly because the modders are unaware) so this page will cover them. Some provided <code>UIelement</code>s have <code>fixedSize</code>, which prevents it being resized. The list of those follows: {|class="wikitable" ! UIelement !align="right"| width !align="right"| height |- | OpCheckBox |align="right"| 24 |align="right"| 24 |- | OpRadioButton |align="right"| 24 |align="right"| 24 |- | OpDragger |align="right"| 24 |align="right"| 24 |- | OpSlider |align="right"| **30* |align="right"| |- | OpSliderSubtle |align="right"| **30* |align="right"| |- | OpComboBox |align="right"| |align="right"| 24 |- | OpColorPicker |align="right"| 150 |align="right"| 150 |- | OpTextBox |align="right"| |align="right"| 24 |- | OpHoldButton |align="right"| rad: |align="right"| ''55'' |} (* The width perpendicular to its length is fixed) == UIelement == UIelement is everything that can be added in <code>OpTab</code>, which is 600x600 canvas. Its sub-categories are [[##UIconfig|UIconfig]] and [[##UItrigger|UItrigger]]. UIelement can be either rectangular (pos and size) or circular (pos and rad), although the vast majority of provided UIelements are rectangular. (''Italic'' properties call <code>OnChange</code> when modified) {|class="wikitable" !width="50%"| Property !width="50%"| |- | ''pos(setter)'' | Sets bottom-left position ''relative'' to its canvas (<code>OpTab</code>/<code>OpScrollBox</code>). |- | ''size'' | The size of the element. (When this is rectangular) |- | ''rad'' | The radius of the element. (When this is circular) |- | description | Infotext that will be shown at the bottom of the screen when MouseOver is true. |- | MouseOver | Whether the mouse cursor is over this element. |} {|class="wikitable" !width="50%"| Method !width="50%"| |- | Hide() | Hides this UIelement, and prevent interaction. |- | Show() | Unhide this UIelement. |- | GetPos() | Returns bottom-left position ''relative'' to its canvas (<code>OpTab</code>/<code>OpScrollBox</code>). (pos(getter) returns ''absolute'' position) |- | Reset() | Reset this UIelement if it’s possible. |- | FrameMultiply(origFrameCount) | (static) When you have a frame counter in Update, use this to accommodate with Many More Fixes’ FPS unlock feature. |- | DTMultiply(deltaTime) | (static) Without MMF’s FPS meddling, this returns somewhere close to <code>1f</code>. Use this for ticking gradual changes. |} === OpLabel === [[File:Label.png|thumb|none|alt=OpLabel Sample|OpLabel Sample]] Simply displays text. (''Italic'' parameters are optional) {|class="wikitable" !width="50%"| Constructor Parameter !width="50%"| Displays text aligned to defined rectangular |- | pos | BottomLeft position relative from the canvas origin. |- | size | Width and height of the rectangle this UIelement occupies. |- | ''text'' | Text to be displayed. Setting it empty will generate Lorem Ipsum for testing. |- | ''alignment'' | Horizontal alignment, whether the text is aligned to left, center, right with the rectangle defined its size. |- | ''bigText'' | Whether to use the bigger font or not. |} {|class="wikitable" !width="50%"| Constructor Parameter !width="50%"| Displays text that goes right from the position |- | posX | Relative distance from the canvas origin to the left side of the UIelement. |- | posY | Relative distance from the canvas origin to bottom side of the UIelement. |- | ''text'' | Text to be displayed. Setting it empty will generate Lorem Ipsum for testing. |- | ''bigText'' | Whether to use the bigger font or not. |} {|class="wikitable" !width="50%"| Property !width="50%"| |- | ''text'' | Text to be displayed. |- | autoWrap | If true, when the text goes over its width, a linebreak will be inserted. |- | ''alignment'' | Horizontal alignment, whether the text is aligned to left, center, right with the rectangle defined its size. |- | ''verticalAlignment'' | Vertical alignment, whether the text is aligned to top, center, bottom with the rectangle defined its size. |- | bumpBehav | <code>null</code> by default. Setting this to other bumpBehaviour will synchronize highlighting. Creating new BumpBehaviour with this label turns itself reactive. |- | color | Colour of the text. |} ==== OpLabelLong ==== A child class of [[###OpLabel|<code>OpLabel</code>]] that is specialized for displaying a long wall of text. This will always use the smaller font. {|class="wikitable" !width="50%"| Constructor Parameter !width="50%"| |- | pos | BottomLeft position relative from the canvas origin. |- | size | Width and height of the rectangle this UIelement occupies. |- | ''text'' | Text to be displayed. Setting it empty will generate Lorem Ipsum for testing. |- | autoWrap | If true, when the text goes over its width, a linebreak will be inserted. |- | ''alignment'' | Horizontal alignment, whether the text is aligned to left, center, right with the rectangle defined its size. |} {|class="wikitable" !width="50%"| Property !width="50%"| |- | allowOverflow | If it’s false, text that goes over the height will be discarded. |} === OpRect === [[File:Rect.png|thumb|none|alt=OpRect Sample|OpRect Sample]] Simple rectangular, useful to make a boundary to group UIelements. Z-order is the order they’re initialized, so for that purpose, initialize OpRect beforehand. {|class="wikitable" ! Constructor Parameter ! |- | pos | BottomLeft position relative from the canvas origin. |- | size | Width and height of the rectangle this UIelement occupies. |- | ''alpha'' | Alpha of the background of the rectangle. |} {|class="wikitable" !width="50%"| Property !width="50%"| |- | colorEdge | The colour of boundary sprites. |- | colorFill | The colour of fill sprites. |- | alpha | Alpha of the background of the rectangle. If doesBump, this gets ignored. |- | doesBump | If true, this rectangle reacts to mouse cursor hovering . |- | bumpBehav | If doesBump, this controls reaction. If not, this stays <code>null</code>. |} === OpImage === [[File:Image.png|thumb|none|alt=OpImage Sample|OpImage Sample]] Displays an image, whether it’s <code>FAtlasElement</code> that’s already loaded in <code>Futile.atlasManager</code>, or <code>Texture2D</code>. {|class="wikitable" ! Constructor Parameter ! Displays Texture2D |- | pos | BottomLeft position relative from the canvas origin. |- | image | Texture2D image to be displayed. |} {|class="wikitable" ! Constructor Parameter ! Displays FAtlasElement |- | pos | BottomLeft position relative from the canvas origin. |- | fAtlasElement | The name of FAtlasElement. |} {|class="wikitable" !width="50%"| Property !width="50%"| |- | ''color'' | The colour of the sprite. |- | ''anchor'' | The anchor of the sprite. (0f, 0f) to set pos as BottomLeft, and (0.5f, 0.5f) to set pos as the centre. |- | ''scale'' | The scale of the sprite. |- | ''alpha'' | The alpha of the sprite. |} You can change the image without making new OpImage. However, you cannot change the Texture2D version to FAtlasElement and vice versa. {|class="wikitable" ! Method ! |- | ChangeImage(newImage) | Swap image to new Texture2D. |- | ChangeElement(newElement) | Swap FAtlasElement to new one. |} === OpScrollBox === OpScrollBox is written by Slime_Cubed. It’s a special UIelement that acts as a canvas, like OpTab. [[File:ScrollBox_Box.png|thumb|none|alt=OpScrollBox Sample - Box|OpScrollBox Sample - Box]] {|class="wikitable" ! Constructor Parameter ! Rectangular ScrollBox inside OpTab |- | pos | BottomLeft position relative from the canvas origin. |- | size | The size of the display. |- | contentSize | Internal length of the scroll direction. |- | ''horizontal'' | Whether this scrolls horizontally or vertically. |- | ''hasBack'' | Whether its boundary will have filled backdrop or not. |- | ''hasSlideBar'' | Whether this will have a scrollbar or not. |} [[File:ScrollBox_Tab.png|thumb|none|alt=OpScrollBox Sample - Tab|OpScrollBox Sample - Tab]] {|class="wikitable" ! Constructor Parameter ! ScrollBox that replaces OpTab |- | tab | BottomLeft position relative from the canvas origin. |- | contentSize | The size of the display. |- | ''horizontal'' | Whether this scrolls horizontally or vertically. |- | ''hasSlideBar'' | Whether this will have a scrollbar or not. |} Think of OpScrollBox as a window that displays a larger canvas inside. The size of this window is the same as <code>size</code>. The size of the canvas inside has <code>contentSize</code> for its scroll-direction length, and the other length matches the width of this window. [[File:ScrollBox_Diagram.png|thumb|none|alt=OpScrollBox Diagram|OpScrollBox Diagram]] The diagram above would be coded like the following. Their <code>pos</code> is relative to the bottom left origin of the canvas inside the OpScrollBox. The result of this code is shown above. <syntaxhighlight lang="c#"> OpScrollBox scb = new OpScrollBox(new Vector2(100f, 100f), new Vector2(240f, 150f), 400f); Tabs[0].AddItems(scb); // Not required if you're using Tab version of constructor scb.AddItems(new OpLabelLong(new Vector2(20f, 20f), new Vector2(120f, 200f)), new OpSlider(new Vector2(160f, 30f), "_", new IntVector2(-20, 20), length: 180, true, 10)); // Use AddItems on OpScrollBox instead of OpTab </syntaxhighlight> {|class="wikitable" !width="50%"| Property !width="50%"| |- | redrawFlags | When this ScrollBox should be redrawn. Never / Always(default) / OnHover / OnKeypress. |- | colorEdge | Edge colour of rectangles. |- | colorFill | Fill colour of rectangles. |- | fillAlpha | Fill alpha of boundary rectangle. |- | doesBackBump | If false, the boundary rectangle does not react with mouseover. |- | ScrollLocked | Whether the scrolling is locked. Manipulated by <code>Lock</code> and <code>Unlock</code> method. |- | ScrollOffset | The visual offset, in pixels, of the contents of this ScrollBox. (&lt;=0) |- | MaxScroll | The value of <code>ScrollOffset</code> at the topmost or rightmost position of the box. (&lt;=0) |- | targetScrollOffset | The target value of <code>ScrollOffset</code>. Change this to smoothly animate scrolling. |} {|class="wikitable" !width="50%"| Method !width="50%"| |- | AddItems(items) | Adds a collection of items to the interior of this ScrollBox. Use this instead of <code>OpTab.AddItems</code> for its children. |- | Lock(stopImmediately) | Locks scrolling. If <code>stopImmediately</code>, ignore <code>targetScrollOffset</code> and stops immediately. |- | UnLock() | Unlocks scrolling. |- | ScrollToTop(''immediate'') | Scrolls to the top/leftmost. If <code>immediate</code>, scrolling animation gets cancelled. |- | ScrollToBottom(''immediate'') | Scrolls to the bottom/rightmost. If <code>immediate</code>, scrolling animation gets cancelled. |- | MarkDirty() | Forces redrawing at the end of this frame. |- | MarkDirty(time) | Forces redrawing for the amount of <code>time</code> in seconds. |} === OpContainer === This is an easy-to-access FContainer for ConfigMenu. {|class="wikitable" ! Constructor Parameter ! |- | pos | The origin of this element relative to the canvas origin. |} {|class="wikitable" !width="50%"| Property !width="50%"| |- | container | Accessible FContainer. You can access this without checking isOptionMenu. (NullRef-proof) |} == UIconfig == <code>UIconfig</code> is a subcategory of [[##UIelement|UIelement]], and has few extra properties and methods. Their value gets saved in <code>ModConfigs</code> folder in json format. If the key is either <code>null</code>, Empty, or starts with <code>_</code>, it is considered <code>cosmetic</code> and its value won’t be saved. For collecting config values, access <code>config</code> dictionary with <code>key</code> you’ve set, in <code>ConfigOnChange</code>. {|class="wikitable" !width="50%"| Property !width="50%"| |- | key | (readonly) Unique key to save and access the value. |- | ''value'' | The value that gets saved. <code>valueInt</code>, <code>valueFloat</code>, and <code>valueBool</code> exist which is useful for designing reactive GUI. |- | greyedOut | If true, the element gets greyed out visually and cannot be interacted with. |- | bumpBehav | <code>BumpBehaviour</code> instance this UIconfig has. |} {|class="wikitable" ! Method ! |- | ForceValue(newValue) | Change <code>value</code> without invoking <code>OnChange()</code>. |} === OpCheckBox === [[File:CheckBox.png|thumb|none|alt=OpCheckBox Sample|OpCheckBox Sample]] [https://en.wikipedia.org/wiki/Checkbox CheckBox] (a.k.a. TickBox) permits the user to make a binary choice. This returns bool (<code>&quot;true&quot;</code> or <code>&quot;false&quot;</code>). Its size is fixed to 24x24. {|class="wikitable" ! Constructor Parameter ! Default constructor |- | pos | BottomLeft position relative from the canvas origin. |- | key | Unique key to save and access the value. |- | ''defaultBool'' | Default value. |} {|class="wikitable" !width="50%"| Constructor Parameter !width="50%"| Lazier version that accepts two float for pos |- | posX | Relative distance from the canvas origin to the left side of the UIelement. |- | posY | Relative distance from the canvas origin to bottom side of the UIelement. |- | key | Unique key to save and access the value. |- | defaultBool | Default value. |} {|class="wikitable" ! Property ! |- | colorEdge | The colour of its boundary and its symbol. |- | colorFill | The colour that fills inside. |} === OpRadioButtonGroup === [[File:RadioButton.png|thumb|none|alt=OpRadioButton Sample|OpRadioButton Sample]] [https://en.wikipedia.org/wiki/Radio_button RadioButton] (a.k.a. OptionButton) permits the user to choose only one of a predefined set of mutually exclusive options. <code>OpRadioButton</code> is ''UIelement'' that ''looks'' like an UIconfig, but isn’t. <code>OpRadioButtonGroup</code>, albeit invisible, is what actually stores the value to be saved. This returns int value. As OpRadioButtonGroup is arbitary, it doesn’t need the <code>pos</code> to be initialized. However, if your OpRadioButtons should be in OpScrollBox, add OpRadioButtonGroup for its child instead of OpTab. {|class="wikitable" ! Constructor Parameter ! Default constructor |- | key | Unique key to save and access the value. |- | ''defaultValue'' | Default value. 0 or higher. |} {|class="wikitable" !width="50%"| Method !width="50%"| |- | buttons | OpRadioButtons that belong to this. Use SetButtons(buttons) to set. |} {|class="wikitable" !width="50%"| Method !width="50%"| |- | SetButtons(buttons) | Binds OpRadioButton to this. This also adds <code>OpRadioButton</code>s to the canvas this is in. |- | Hide() | Calls Hide() for all children. |- | Show() | Calls Show() for all children. |- | SetColorEdge(newColor) | Changes colorEdge of all children. |- | SetColorFill(newColor) | Changes colorFill of all children. |} Example: <syntaxhighlight lang="c#"> OpRadioButtonGroup group = new OpRadioButtonGroup("MyOption"); Tabs[1].AddItems(group); // Add this to canvas before calling SetButtons group.SetButtons(new OpRadioButton[] { new OpRadioButton(300f, 450f), new OpRadioButton(350f, 450f) }); // SetButtons adds params to the canvas the group is in, so no need to call AddItems again. </syntaxhighlight> ==== OpRadioButton ==== This is an UIelement and it alone does not do anything. Its size is fixed to 24x24. {|class="wikitable" ! Constructor Parameter ! Default constructor |- | pos | BottomLeft position relative from the canvas origin. |} {|class="wikitable" !width="50%"| Constructor Parameter !width="50%"| Lazier version that accepts two float for pos |- | posX | Relative distance from the canvas origin to the left side of the UIelement. |- | posY | Relative distance from the canvas origin to bottom side of the UIelement. |} It has properties that’s the same name as UIconfigs, and they do identical things. {|class="wikitable" !width="50%"| Property !width="50%"| |- | greyedOut | If true, locks interaction with this button. The users still can interact with other OpRadioButton in the group. |- | colorEdge | The colour of its boundary and its symbol. |- | colorFill | The colour that fills inside. |- | ''value'' | The value of this, although this doesn’t get saved. ''valueBool'' returns this in bool. |- | bumpBehav | BumpBehaviour instance that’s bound to this. |} === OpDragger === [[File:Dragger.png|thumb|none|alt=OpDragger Sample|OpDragger Sample]] Rain World Dragger is a small box with a number, which the users can adjust by holding the mouse and move vertically. It is useful for cramping adjustable int value in a tight space. This returns int value. Its size is fixed to 24x24. {|class="wikitable" ! Constructor Parameter ! Default constructor |- | pos | BottomLeft position relative from the canvas origin. |- | key | Unique key to save and access the value. |- | ''defaultInt'' | Default value. |} {|class="wikitable" !width="50%"| Constructor Parameter !width="50%"| Lazier version that accepts two float for pos |- | posX | Relative distance from the canvas origin to the left side of the UIelement. |- | posY | Relative distance from the canvas origin to bottom side of the UIelement. |- | key | Unique key to save and access the value. |- | ''defaultInt'' | Default value. |} {|class="wikitable" ! Property ! |- | min | The minimum number this dragger is allowed to go. (default: 0) |- | max | The maximum number this dragger is allowed to go. (default: 99) |- | colorEdge | The colour of its boundary. |- | colorFill | The colour that fills inside. |- | colorText | The colour of its number inside. |} === OpSlider === [[File:Slider.png|thumb|none|alt=OpSlider Sample|OpSlider Sample]] [https://en.wikipedia.org/wiki/Slider_(computing) Slider] (a.k.a. TrackBar) allows the users to set value by dragging the indicator. Clicking a point on the slider also works. This returns int value. The width perpendicular to its length is fixed to 30. {|class="wikitable" ! Constructor Parameter ! Default constructor. |- | pos | BottomLeft position relative from the canvas origin. |- | key | Unique key to save and access the value. |- | range | Inclusive range of value. |- | length | The length of this element. |- | ''vertical'' | |- | ''defaultValue'' | Default value. |} {|class="wikitable" ! Constructor Parameter ! Length = range * multi |- | pos | BottomLeft position relative from the canvas origin. |- | key | Unique key to save and access the value. |- | range | |- | ''multi'' | How much pixels length each tick would take. |- | ''vertical'' | |- | ''defaultValue'' | Default value. |} ==== OpSliderSubtle ==== [[File:SliderSubtle.png|thumb|none|alt=OpSliderSubtle Sample|OpSliderSubtle Sample]] === OpKeyBinder === {{todo}} === OpComboBox === [[File:ComboBox.png|thumb|none|alt=OpComboBox Sample|OpComboBox Sample]] [https://en.wikipedia.org/wiki/Combo_box ComboBox] is a combination of [https://en.wikipedia.org/wiki/Drop-down_list Drop-down List] and SearchBox. ==== OpResourceSelector ==== {{todo}} ==== ListItem ==== While this technically belongs to [[##Custom-Classes|Custom Classes]], this is currently only used in <code>OpComboBox</code> so it will be included here. === OpColorPicker === [[File:ColorPicker.png|thumb|none|alt=OpColorPicker Sample|OpColorPicker Sample]] [https://en.wikipedia.org/wiki/Color_picker ColorPicker] (a.k.a. ColorChooser) allows the users to select a Color. OpColorPicker has four modes of selecting Color: RGB(Red/Green/Blue), HSL(Hue/Satuation/Lightness), PLT(Palette), and HEX (which can be copied and pasted from Clipboard). OpColorPicker stores value in HEX, so <code>OpColorPicker.HexToColor</code> method comes handy converting that. === OpTextBox === [https://en.wikipedia.org/wiki/Text_box TextBox] (a.k.a. TextField or TextEntryBox) allows the users to input text information. == UItrigger == {{todo}} === OpSimpleButton === SimpleButton is a [https://en.wikipedia.org/wiki/Button_(computing) PushButton] that allows the users to trigger an event. ==== OpSimpleImageButton ==== {{todo}} === OpHoldButton === {{todo}} [[File:HoldButton.png|thumb|none|alt=OpHoldButton Sample|OpHoldButton Sample]] == Custom Classes == {{todo}} === DyeableRect === {{todo}} === BumpBehaviour === {{todo}} === FTexture === {{todo}} === FCursor === {{todo}} === LabelTest === {{todo}} === LoremIpsum === {|class="wikitable" !width="50%"| Properties !width="50%"| |- | *_init* | Whether this is initialized in ConfigMenu or not. The same as <code>OptionInterface.isOptionMenu</code>. |- | ''menu'' | Rain World Menu instance this element is belong to. |- | ''owner'' | Rain World Page instance this element is belong to. |- | ''tab'' | OpTab instance this element is in. |- | ''subObjects'' | <code>MenuObject</code> instances this element has. |- | ''myContainer'' | FContainer that this element has. It gets initialized in constructor ''only'' when <code>_init</code>. |- | ''isHidden'' | Whether this is hidden and not visible. |- | ''fixedSize'' | If this is not null, this element’s size will always be this. (''fixedRad'' does the similar) |- | *_soundFill* | Add number (in proportion with sound effect’s length) to this whenever you’re playing soundeffect. |- | *_soundFilled* | If this is true, avoid excuting <code>menu.PlaySound</code> |} 1cb6a15f276fbb6c7020e75047ff6e9f9eb1c469 MonoMod Patches 0 107 432 254 2023-03-31T14:07:08Z Thalber 3 add legacy tag wikitext text/x-wiki {{Legacy}} {{Cleanup}} '''MonoModPatches''' or '''MMPatches''' are one of the simplest ways of modifying vanilla code. They can be used with current version of our [[BepInEx]] package. MonoMod's [https://github.com/MonoMod/MonoMod/blob/master/README.md README] contains a description of this method. Short summary and RW-specific aspects are presented below. == Creation == * Create a project referencing both <code>MonoMod.exe</code> and <code>AssemblyCSharp.dll</code> * Create a type deriving from target class * Mark your class for patching. This can be done in two ways: *# Place your class in the exact same namespace and name it <code>patch_OriginalNamehere</code> (<code>patch_Player</code> to patch <code>Player</code>) *# Denote your class with <code>MonoModPatch</code> attribute like the following example <!--(<code>Custom</code>)--> <syntaxhighlight lang="csharp"> [MonoModPatch("global::Player")] //"global::" is the namespace for classes appearing "without a namespace" public class CustomPlayer : Player { } </syntaxhighlight> * For every method to patch, use the following pattern: <syntaxhighlight lang="csharp"> [MonoModPatch("global::Player")] public class CustomPlayer : Player { public extern void orig_Update(bool eu); public override void Update(bool eu) { //do your things orig_Update(eu); // original method body is inserted at the site of this call. Omit to not use original code at all (also disables layering MMPatches). //do your things } } </syntaxhighlight> To access a private member, create one with matching signature (type / name / params etc) and denote it with <code>MonoModIgnore</code> attribute. To patch a non-override public method, use <code>new</code> to hide the vanilla method for the compiler. === Things to note === * MMPatches should not be shipped in the same assembly as partmods/[[BepInPlugins]]. If that is done, there is only a small chance doing that will ''not'' turn your game into an firecracker plant. * <code>MonoModRules</code> described in MonoMod readme does not seem to coexist nicely with BepInEx. ''More testing is required to narrow down where things go terribly wrong.'' == Usage == MMPatches have to be named as following: <code>AssemblyCSharp.[modName].mm.dll</code>. They are loaded from <code>Rain World/BepInEx/monomod/</code> ''at preloader time''. [[BOI]] renames files automatically in a futile attempt to make the process more intuitive for the end user. [[Category:Code Mods]] 2f1ab74adb49c1c2100f36d63c1c916c9c47d523 EnumExtender 0 94 433 300 2023-03-31T14:16:57Z Thalber 3 add legacy tag wikitext text/x-wiki {{Legacy}} {{Toolinfo |type=Dependency library |authors=Bee |license=CC0 |releases=[https://github.com/aaay-aaay/EnumExtender source], [https://beestuff.pythonanywhere.com/audb/api/mods/0/1/download/latest latest build] }} '''{{PAGENAME}}''' or '''EE''' is a tool mod which allows adding entries to <code>Enum</code>s. It is widely used as a dependency library. == Features == EE allows the user to add entries to enums at runtime in two ways: * Automatic (does not require referencing EE assembly in your project) * Manual (requires referencing EE assembly in your project) == Usage == === Automatic extension === On initialization, EE scans all loaded classes, looking for <code>public static class</code> with names starting with <code>EnumExt_</code>. Extensions are created from <code>public static</code> fields with the type of target enum. Created entries have the same name as the field, and the field gets the value of the new entry. Example use: <syntaxhighlight lang="csharp"> public static class EnumExt_MyMod { // You can have multiple EnumExt_ classes in your assembly if you need multiple items with the same name for the different enum //this adds entry "Vultures" to enum "CreatureCommnuities.CommunityID" public static CreatureCommnuities.CommunityID Vultures; //this adds "YellowishWhite" to "SlugcatStats.Name" public static SlugcatStats.Name YellowishWhite; public static SlugcatStats.Name WhitishYellow; } </syntaxhighlight> To access these new enum items, instead of <code>[enum].[item]</code>, use that static field. To compare it, use <code>if</code> statements (unfortunately, you can not use static fields for branches in a <code>switch</code> statement). Example use: <syntaxhighlight lang="csharp"> public static SlugStatsPatch(On.SlugcatStats.orig_ctor orig, SlugcatStats stats, int slugcatNumber, bool malnourished) {     orig.Invoke(stats, slugcatNumber, malnourished);     if (stats.name == EnumExt_MyMod.YellowishWhite)     {         stats.runspeedFac = 1.2f;         stats.poleClimbSpeedFac = 1.25f;         stats.corridorClimbSpeedFac = 1.2f;     } } </syntaxhighlight> However, if EnumExtender is not present in runtime (for instance, the user forgot to install EnumExtender), these fields won't be initialized and will always stay at 0. This can be used to easily detect whether EnumExtender is installed or not. <syntaxhighlight lang="csharp"> public static bool HasEnumExt => (int)EnumExt_MyMod.YellowishWhite > 0; // This property returns true after EE initializes (after OnEnable) </syntaxhighlight> ==== Switch statement workaround ==== If you have multiple new items and really want to use switches, you can do something like the following: <syntaxhighlight lang="csharp"> public static class EnumSwitch { //the intermediary enum     public enum SlugcatStatsName     {         DEFAULT = -1, // unrelated to this mod         YellowishWhite,         WhitishYellow     };     public static SlugcatStatsName GetSlugStatsNameInterm(SlugcatStats.Name name)     {         if (!HasEnumExt) { return SlugcatStatsName.DEFAULT; } // EnumExt is not installed         if (name == EnumExt_MyMod.YellowishWhite) { return SlugcatStatsName.YellowishWhite; }         if (name == EnumExt_MyMod.WhitishYellow) { return SlugcatStatsName.WhitishYellow; }         return SlugcatStatsName.DEFAULT;     } } </syntaxhighlight> And when you need to use switch later, <syntaxhighlight lang="csharp"> switch (EnumSwitch.GetSlugStatsNameInterm(name)) {     default:     case SlugcatStatsName.DEFAULT: break;     case SlugcatStatsName.YellowishWhite:         break;     case SlugcatStatsName.WhitishYellow:         break; } </syntaxhighlight> <!--ehhhh this was a bad idea '''Alternatively''', if you want to use one switch statement containing checks for both vanilla and intermediary enum, you can # give an explicit value to the interm enum, ideally some really large numbers so that it doesn't collide with any vanilla values # modify interm method (<code>GetSlugStatsNameInterm</code> in the example) to return an int and return original value as int when EE is not installed # instead of switching over <syntaxhighlight lang="charp"> //... //... </syntaxhighlight> --> === Manual extension === This method is useful when you don't know what name your new entries will have to have. It is more cumbersome to use and less safe, but # Ensure that EE has been initialized. You can either wait until the <code>EnumExt_</code> get appropriate values, or call <code>PastebinMachine.EnumExtender.EnsureInit()</code> # Call <code>PastebinMachine.EnumExtender.AddDeclaration(Type, string)</code> one or more times. First parameter is <code>Type</code> of the enum, second is the name of new entry. '''Ensuring there are no name collisions is on you!''' # Call <code>PastebinMachine.EnumExtender.ExtendEnumsAgain</code> ''once'' to register all your new enums. '''NOTE''': Last step may have a noticeable overhead, and each call to <code>ExtendEnumsAgain</code> causes a small but permanent memory leak. Do not overuse. <code>ExtendEnumsAgain</code> does not return the added values, you have to obtain them manually through <code>Enum.GetNames()</code> or <code>Enum.GetValues()</code>. Storing the resulting values correctly is the user's responsibility. == Summary == Both modes allow you to use methods like <code>Enum.Parse</code> with extended values freely. RW codebase uses enums pretty much everywhere, so EnumExtender is a often a vital dependency. [[Category:Code Mods]] [[Category:Dependencies]] dddaf7be1cf59516d63a1fc3751d8485550b3ad8 Downpour Reference/Mod Directories 0 145 434 402 2023-03-31T14:45:10Z Thalber 3 wikitext text/x-wiki [[File:RemixModFolderAndInfoJson.png|thumb|Example of a correctly placed Remix mod main folder and a valid modinfo.json file.]] Each mod in Downpour is stored as a subfolder inside the <code>RainWorld_Data/StreamingAssets/mods</code> directory. This subfolder contains all metadata, file modifications and overrides, assets, and code modules (DLL files) that define the mod's contents and functionality. == ModInfo JSON == Each mod should have a <code>modinfo.json</code> file included in the top level directory of the mod. This JSON file defines the metadata for the mod, mainly the information that will be displayed for that mod within the REMIX menu. The following key-value pairs exist for this JSON file: {|class="wikitable" ! Key !! Meaning |- | id || This is a unique string identifier for this mod. This identifier should never be changed. Recommended to be a lower-case string with no spaces. Other mods will reference this ID to refer to your mod, such as when listing mod requirements. |- | name || This is the title of your mod that will be shown and listed in the REMIX menu. |- | version || This is a string specifying the current version number of your mod. |- | target_game_version || The version number of Rain World this mod was made for. Note that this must start with a "v". (''The current game version can be found in <code>RainWorld_Data/StreamingAssets/GameVersion.txt</code>'') |- | authors || A string listing the authors of the mod. The &lt;LINE&gt; keyword can be used to add a breakline. If the authors string is too long to be displayed directly, it will be converted to a credits roll in the REMIX menu. |- | description || A longer description of the functionality of the mod, to be displayed in the REMIX menu. The &lt;LINE&gt; keyword can be used to add a breakline. |- | youtube_trailer_id || Optionally, specify the ID for a YouTube video to associate with this mod as a preview trailer. The ID is the text after ?v= in a YouTube video URL. |- | requirements || An array of strings specifying other mods which must be installed to use this mod. Each string in the array should match the '''id''' key of the required mod. |- | requirements_names || A parallel array to the "'''requirements'''" array, which you can use to display more user friendly names for the requirements in the REMIX menu rather than displaying their internal '''id''' string. |- | tags || An array of strings specifying the Steam Workshop tags which will be added to this mod. These should match the tags listed on the game's workshop page. |- | checksum_override_version || An optional boolean parameter. If false, or omitted, the mod will be considered &quot;updated&quot; if changes are found to any files in the mod's folder. If true, the mod will only be considered &quot;updated&quot; if the value of the '''version''' parameter changes. (''See additional notes in the next section below'') |} An example modinfo.json file contents: <syntaxhighlight lang="json"> { "id": "testmod", "name": "Test Mod", "version": "1.0", "target_game_version": "v1.5", "authors": "AndrewFM", "description": "This mod does something interesting, probably!", "youtube_trailer_id": "u-cuf39rK8g", "requirements": ["bestmod", "vrmod"], "requirements_names": ["That Other Mod", "Virtual Reality Support"], "tags": ["Game Mechanics"], "checksum_override_version": false } </syntaxhighlight> In addition to the modinfo.json file, the mod directory can also include a '''thumbnail.png''' image to be displayed in the REMIX menu. This should be an image with 16:9 aspect ratio, recommended to be at least 640x360 pixels large. Additionally, the file size of this thumbnail image should remain below 1 MB. === Checksum Override === Note that the "'''checksum_override_version'''" flag can also be useful during development of your mod when file changes will be frequent. This will suppress the checksum validation and prevent the normal workflow of resolving file changes, merges, and mod conflicts, which can save you time when relaunching the game and/or enabling your mod. However, it is recommended to turn this flag back off before distributing your mod. If you leave it enabled and forget to update your mod's version before distributing the update, it may break your mod for people who already had it installed and enabled, as it will suppress the default update resolution workflow. == Overwriting Files == The contents of the mod folder are a mirror of the StreamingAssets folder. For example, if you wanted your mod to replace the image file at: <pre>      "Assets/StreamingAssets/futile/resources/illustrations/maintitle.png" </pre> with a different image, you would place the new image at: <pre>      "your-mod-folder/futile/resources/illustrations/maintitle.png" </pre> Since the directory structure and file name match one of the original game's files, the game will use the version from your mod directory instead of the original version of the file, whenever your mod is enabled. In some cases files outside the StreamingAssets folder can be modified as well. For example to modify sound effects (Assets/LoadedSoundEffects) your folder structure would be: <pre>      "your-mod-folder/futile/resources/loadedsoundeffects/..." </pre> Or to modify music files (Assets/Music), the structure would be: <pre>      "your-mod-folder/futile/resources/music/..." </pre> Refer to [[Downpour Reference/Modification Files]] for other ways to modify existing files other than completely overwriting their contents, for better mod compatibility. == AssetManager == Whenever referencing any asset files from disk in your code (whether they be files from within your mod's folder, or files within the base game's folders), you should use the static utility functions offered by the <code>AssetManager</code> class. This ensures the file path to the correct version of the file is used based on which mods are enabled or disabled, following the logic above. For example: <pre>AssetManager.ResolveFilePath(&quot;futile/resources/illustrations/maintitle.png&quot;);</pre> This would return the file path to the vanilla maintitle.png file. However, if the example mod described in the previous section were enabled, this instead would return the file path to that mod's overwritten version of maintitle.png. The available utility functions are: {|class="wikitable" ! Method !! Meaning |- | '''ResolveFilePath(path)''' || Return the correct path to the given file based on enabled/disabled mods. |- | '''ResolveDirectory(path)''' || Return the correct path to the given subdirectory based on enabled/disabled mods. |- | '''ListDirectory(path)''' || Returns all unique files contained in all versions of the given subdirectory based on enabled/disabled mods. |- | '''ListDirectory(path, true)''' || Returns all unique subdirectories contained in all versions of the given subdirectory based on enabled/disabled mods. |} To give an example of ListDirectory, consider a hypothetical vanilla directory at: <pre>      "Assets/StreamingAssets/futile/resources/example" </pre> which contained the files "a.txt", "b.txt", and "c.txt". Then say you created a mod which included the folder: <pre>      "your-mod-folder/futile/resources/example" </pre> which contained the files "c.txt", and "d.txt". Then when the code below is executed: <pre> AssetManager.ListDirectory("futile/resources/example"); </pre> If your mod is disabled, the files "a.txt" (vanilla), "b.txt" (vanilla), "c.txt" (vanilla) would be returned. If your mod is enabled, the files "a.txt" (vanilla), "b.txt" (vanilla), "c.txt" (modded), "d.txt" (modded) would be returned. 619900e1c2a74f26a1602f6a7a41d2260283e0d2 Category:Legacy 14 184 437 2023-03-31T14:48:45Z Thalber 3 init wikitext text/x-wiki This category contains pages that are only relevant for old versions of Rain World. c0fe3d70580e760574fa45d508057bd78b439f58 441 437 2023-04-04T02:56:11Z Thalber 3 wikitext text/x-wiki This category contains pages with information that is only relevant for old versions of Rain World. 840fb60a52489c7ca5ee2eeed43d743d7cdf85e2 Logs 0 185 438 2023-03-31T15:18:14Z Thalber 3 Created page with "{{todo|target=page}} {| class="wikitable" |+ Rain World generates the following log files |- ! File !! Function !! Frequently useful |- | <code>exceptionLog.txt</code> || vanilla errors and unhandled mod errors || Yes |- | <code>consoleLog.txt</code> || vanilla log calls || No |- | <code>BepInEx/LogOutput.log</code> || logs from [[BepInPlugins]] || Yes |}" wikitext text/x-wiki {{todo|target=page}} {| class="wikitable" |+ Rain World generates the following log files |- ! File !! Function !! Frequently useful |- | <code>exceptionLog.txt</code> || vanilla errors and unhandled mod errors || Yes |- | <code>consoleLog.txt</code> || vanilla log calls || No |- | <code>BepInEx/LogOutput.log</code> || logs from [[BepInPlugins]] || Yes |} d8f1bbdb938b01c702d83ea62dc431245bee5e4d Remix Menu 0 186 439 2023-03-31T20:10:39Z O645 140 very rough guide for making remix menus. sorry this is so ugly!!!! wikitext text/x-wiki {{Cleanup}} {{todo}} Remix uses ConfigMachine for it's option interfaces. == Creating an options menu: == Options menus are inherited from OptionInterface <syntaxhighlight lang="csharp"> public class OptionsMenu : OptionInterface { } </syntaxhighlight> You will want to store your configurable variables as: <code> public readonly Configurable<TYPE> NAME; </code>, then initialize them in the constructor: <syntaxhighlight lang="csharp"> public OptionsMenu(Plugin plugin) { NAME = this.config.Bind<TYPE>("KEY", DEFAULTVALUE); } </syntaxhighlight> === Setting up the interface === In your <code>Initialize()</code> method: <syntaxhighlight lang="csharp"> var opTab = new OpTab(this, "TABNAME"); //Create a tab. this.Tabs = new[]{ opTab //Add the tab into your list of tabs. }; UIelement[] UIarrayOptions = new[]{ //create an array of ui elements { new OpLabel(10f,550f,"Options",true), //Creates a label at 10,550 with big text saying "Options" } opTab.AddItems(UIarrayOptions); //adds the elements to the tab </syntaxhighlight> A list of all UI elements in ConfigMachine is available [[ConfigMachine/Provided_Elements|here]]. === Connecting your options interface === You will need to setup an instance of your optionsmenu in the main plugin: <syntaxhighlight lang="csharp"> private OptionsMenu options; public Plugin() { options = new OptionsMenu(this); } </syntaxhighlight> Then in your OnModsInit hook, add in <code> MachineConnector.SetRegisteredOI("PLUGINID", options);</code>. <br> Plugin id must be '''EXACT''' to the id specified in your mod's <code>ModInfo.json</code> You can retrieve the values from the option menu simply by doing <code> options.name.value </code>. <br> For player specific values you can have the option value as an array, and simply do <code> options.name[self.playerNumber].value to return that player's version. acc89c9bb292cd7e286d70b7c71e009a12a597f1 449 439 2023-04-04T19:36:02Z Thalber 3 wikitext text/x-wiki {{Cleanup}} {{todo}} Remix uses ConfigMachine for it's option interfaces. == Creating an options menu: == Options menus are inherited from OptionInterface <syntaxhighlight lang="csharp"> public class OptionsMenu : OptionInterface { } </syntaxhighlight> You will want to store your configurable variables as: <code> public readonly Configurable<TYPE> NAME; </code>, then initialize them in the constructor: <syntaxhighlight lang="csharp"> public OptionsMenu(Plugin plugin) { NAME = this.config.Bind<TYPE>("KEY", DEFAULTVALUE); } </syntaxhighlight> === Setting up the interface === In your <code>Initialize()</code> method: <syntaxhighlight lang="csharp"> var opTab = new OpTab(this, "TABNAME"); //Create a tab. this.Tabs = new[]{ opTab //Add the tab into your list of tabs. }; UIelement[] UIarrayOptions = new[]{ //create an array of ui elements { new OpLabel(10f,550f,"Options",true), //Creates a label at 10,550 with big text saying "Options" } opTab.AddItems(UIarrayOptions); //adds the elements to the tab </syntaxhighlight> A list of all UI elements in ConfigMachine is available [[ConfigMachine/Provided_Elements|here]]. === Connecting your options interface === You will need to setup an instance of your optionsmenu in the main plugin: <syntaxhighlight lang="csharp"> private OptionsMenu options; public Plugin() { options = new OptionsMenu(this); } </syntaxhighlight> Then in your OnModsInit hook, add a call to register your interface: <syntaxhighlight lang="csharp"> public Hook_OnModsInit(On.RainWorld.orig_OnModsInit orig, RainWorld self) { orig(self); try { MachineConnector.SetRegisteredOI("PLUGINID", options); } catch (Exception ex) { /* make sure to error-proof your hook, otherwise the game may break in a hard-to-track way and other mods may stop working */ } } </syntaxhighlight> <br> Plugin id must be '''EXACT''' to the id specified in your mod's <code>ModInfo.json</code> You can retrieve the values from the option menu simply by doing <code> options.name.value </code>. <br> For player specific values you can have the option value as an array, and simply do <code> options.name[self.playerNumber].value to return that player's version. 03a7ff428078a46cf343477c414d63ddff2becdf 450 449 2023-04-04T19:50:00Z Thalber 3 wikitext text/x-wiki {{Cleanup}} {{todo}} Remix uses ConfigMachine for it's option interfaces. == Creating an options menu: == Options menus are inherited from OptionInterface <syntaxhighlight lang="csharp"> public class OptionsMenu : OptionInterface { } </syntaxhighlight> You will want to store your configurable variables as: <code> public readonly Configurable<TYPE> NAME; </code>, then initialize them in the constructor: <syntaxhighlight lang="csharp"> public OptionsMenu(Plugin plugin) { NAME = this.config.Bind<TYPE>("KEY", DEFAULTVALUE); } </syntaxhighlight> '''IMPORTANT''': Config entry keys should only contain Latin letters and underscores! Putting an unexpected character will throw an exception === Setting up the interface === In your <code>Initialize()</code> method: <syntaxhighlight lang="csharp"> var opTab = new OpTab(this, "TABNAME"); //Create a tab. this.Tabs = new[]{ opTab //Add the tab into your list of tabs. }; UIelement[] UIarrayOptions = new[]{ //create an array of ui elements { new OpLabel(10f,550f,"Options",true), //Creates a label at 10,550 with big text saying "Options" } opTab.AddItems(UIarrayOptions); //adds the elements to the tab </syntaxhighlight> A list of all UI elements in ConfigMachine is available [[ConfigMachine/Provided_Elements|here]]. === Connecting your options interface === You will need to setup an instance of your optionsmenu in the main plugin: <syntaxhighlight lang="csharp"> private OptionsMenu options; public Plugin() { options = new OptionsMenu(this); } </syntaxhighlight> Then in your OnModsInit hook, add a call to register your interface: <syntaxhighlight lang="csharp"> public Hook_OnModsInit(On.RainWorld.orig_OnModsInit orig, RainWorld self) { orig(self); try { MachineConnector.SetRegisteredOI("PLUGINID", options); } catch (Exception ex) { /* make sure to error-proof your hook, otherwise the game may break in a hard-to-track way and other mods may stop working */ } } </syntaxhighlight> <br> Plugin id must be '''EXACT''' to the id specified in your mod's <code>ModInfo.json</code> You can retrieve the values from the option menu simply by doing <code> options.name.value </code>. <br> For player specific values you can have the option value as an array, and simply do <code> options.name[self.playerNumber].value to return that player's version. a4c9dc2107132af31a005d1682bcf22440197676 451 450 2023-04-04T19:55:13Z Thalber 3 wikitext text/x-wiki {{Cleanup}} {{todo}} Remix uses ConfigMachine for it's option interfaces. == Creating an options menu: == Options menus are inherited from OptionInterface <syntaxhighlight lang="csharp"> public class OptionsMenu : OptionInterface { } </syntaxhighlight> You will want to store your configurable variables as: <code> public readonly Configurable<TYPE> NAME; </code>, then initialize them in the constructor: <syntaxhighlight lang="csharp"> public OptionsMenu(Plugin plugin) { NAME = this.config.Bind<TYPE>("KEY", DEFAULTVALUE); } </syntaxhighlight> '''IMPORTANT''': Config entry keys should only contain Latin letters and underscores! Putting an unexpected character will throw an exception === Setting up the interface === In your <code>Initialize()</code> method: <syntaxhighlight lang="csharp"> var opTab = new OpTab(this, "TABNAME"); //Create a tab. this.Tabs = new OpTab[] { opTab //Add the tab into your list of tabs. }; UIelement[] UIarrayOptions = new UIelement[] { //create an array of ui elements { new OpLabel(10f, 550f, "Options", true), //Creates a label at 10,550 with big text saying "Options" }; opTab.AddItems(UIarrayOptions); //adds the elements to the tab </syntaxhighlight> A list of all UI elements in ConfigMachine is available [[ConfigMachine/Provided_Elements|here]]. === Connecting your options interface === You will need to setup an instance of your optionsmenu in the main plugin: <syntaxhighlight lang="csharp"> private OptionsMenu options; public Plugin() { options = new OptionsMenu(this); } </syntaxhighlight> Then in your OnModsInit hook, add a call to register your interface: <syntaxhighlight lang="csharp"> public Hook_OnModsInit(On.RainWorld.orig_OnModsInit orig, RainWorld self) { orig(self); try { MachineConnector.SetRegisteredOI("PLUGINID", options); } catch (Exception ex) { /* make sure to error-proof your hook, otherwise the game may break in a hard-to-track way and other mods may stop working */ } } </syntaxhighlight> <br> Plugin id must be '''EXACT''' to the id specified in your mod's <code>ModInfo.json</code> You can retrieve the values from the option menu simply by doing <code> options.name.value </code>. <br> For player specific values you can have the option value as an array, and simply do <code> options.name[self.playerNumber].value to return that player's version. c2e3d362362ae2dcd4c0463e58d7a4252cccd14c Rain World Code Structure 0 187 440 2023-04-04T02:47:00Z Thalber 3 init wikitext text/x-wiki {{todo|target=article}} This article describes how Rain World vanilla code is laid out, and relationships between different parts. {| class="wikitable" |+ Subsections |- ! Subsection !! Description |- | [[/RainWorld]] || Singleton holding the game |- | [[/Options]] || Class containing user settings |- | [[/ProcessManager_and_Subprocesses]] || Different modes the game can operate in |- | [[/GameSession]] || Different gamemodes (arena/story/safari) |- | [[/Save_Data]] || Different types of save data and rules of its saving/erasing |- | [[/LOD]] || Two Level Of Detail modes game entities inside a GameSession can exist in |- | [[/World]] || Holds your journey together |- | [[/Rooms]] || Building blocks of a world |- | [[/AbstractWorldEntity_Inheritance]] || Different types of Abstract [[/LOD]] entities |- <!--| [[/AbstractCreature]] || Creatures existing in abstract [[/LOD]]. |---> | [[/Abstract_AI]] || AI for abstract layer creatures (see [[/AbstractWorldEntity_Inheritance]]) |- | [[/CreatureState_Inheritance]] || Different states of creatures |- | [[/UpdatableAndDeletable_Inheritance]] || The most basic realize world item and what kinds of children it can have |- | [[/PhysicalObject_Basics]] || Class for things that have collision. Dependent on AbstractPhysicalObject ([[/AbstractWorldEntity_Inheritance]]) |- | [[/PhysicalObject_Inheritance]] || Classification of physical items. |- <!--| [[/Creature]] || Creatures existing in realized [[/LOD]] ([[/PhysicalObject_Inheritance]]). |---> | [[/Realized_AI]] || AI for realized level creatures (base class: ArtificialIntelligence) (see [[/PhysicalObject_Inheritance]]) |- | [[/GraphicsModule]] || Some [[/PhysicalObject]]s separate their graphics into a separate class that is only brought into existence when they are on screen |- | [[/ComplexGraphicsModule]] || Graphics modules for creatures with exceptionally convoluted draw logic are modular |- | [[/RoomCamera]] || Single in vanilla, not so much with mods |- | [[/Physics]] || Where, when and how collisions are calculated |- | [[/Sound_System]] || SFX and music |- | [[/MSC_Namespace_and_Conditional_Enums]] || When and where code exclusive to the DLC is included or excluded |} 2050f223912c5a29350d3a85bbb7e8ba15b9d516 Rain World Code Structure/RainWorld 0 188 442 2023-04-04T03:21:03Z Thalber 3 init wikitext text/x-wiki {{todo}} '''RainWorld''' is a singleton [https://docs.unity3d.com/ScriptReference/MonoBehaviour.html MonoBehavior] that contains all of Rain World's code inside it - menus, game loop, options, etc. == Notable members == {| class="wikitable sortable" |+ |- ! Name !! Kind !! Description |- | processManager || field || ProcessManager object that contains information about current game loops (menu / game session / pause menu etc) |- | Shaders || field || Dictionary of shaders used by the game, keyed by name. Make sure to add to add your custom shaders here if you want to make them accessible by other mods. |- | options || field || [[Rain_World_Code_Structure/Options|Options]] object that contains current user settings, including input config. |- | setup || field || A struct containing special setup values that can change some rules of the game (such as cycle length override). |- | GAME_VERSION_STRING || constant || Current game version as a string. |- | PreModsDisabledEnabled || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files/Mod_Lifecycle_Functions]] |- | OnModsEnabled || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files/Mod_Lifecycle_Functions]] |- | OnModsDisabled || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files/Mod_Lifecycle_Functions]] |- | PostModsDisabledEnabled || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files/Mod_Lifecycle_Functions]] |- | PreModsInit || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files/Mod_Lifecycle_Functions]] |- | OnModsInit || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files/Mod_Lifecycle_Functions]] |- | PostModsInit || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files/Mod_Lifecycle_Functions]] |- | LoadResources || method || Called when assets (such as spritesheets) are bulk loaded from disk to memory. |- | UnloadResources || method || Called before LoadResources needs to be called again. |- | LoadSetupValues || method || Loads setup values from <code>setup.txt</code> if one exists. Don't look inside. |} b00098b7aed033d25f244731bbd0e9224184fb7f 443 442 2023-04-04T03:22:14Z Thalber 3 wikitext text/x-wiki {{todo}} '''RainWorld''' is a singleton [https://docs.unity3d.com/ScriptReference/MonoBehaviour.html MonoBehavior] that contains all of Rain World's code inside it - menus, game loop, options, etc. == Notable members == {| class="wikitable sortable" |+ |- ! Name !! Kind !! Description |- | processManager || field || ProcessManager object that contains information about current game loops (menu / game session / pause menu etc) |- | Shaders || field || Dictionary of shaders used by the game, keyed by name. Make sure to add to add your custom shaders here if you want to make them accessible by other mods. |- | options || field || [[Rain_World_Code_Structure/Options|Options]] object that contains current user settings, including input config. |- | setup || field || A struct containing special setup values that can change some rules of the game (such as cycle length override). |- | GAME_VERSION_STRING || constant || Current game version as a string. |- | PreModsDisabledEnabled || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files#Mod_Lifecycle_Functions]] |- | OnModsEnabled || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files#Mod_Lifecycle_Functions]] |- | OnModsDisabled || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files#Mod_Lifecycle_Functions]] |- | PostModsDisabledEnabled || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files#Mod_Lifecycle_Functions]] |- | PreModsInit || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files#Mod_Lifecycle_Functions]] |- | OnModsInit || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files#Mod_Lifecycle_Functions]] |- | PostModsInit || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files#Mod_Lifecycle_Functions]] |- | LoadResources || method || Called when assets (such as spritesheets) are bulk loaded from disk to memory. |- | UnloadResources || method || Called before LoadResources needs to be called again. |- | LoadSetupValues || method || Loads setup values from <code>setup.txt</code> if one exists. Don't look inside. |} b4a3e17d035d317d74ac64bdc4ac9e8c7e4c2d9a Custom Regions Support 0 101 444 298 2023-04-04T12:59:32Z Cashewww 2 added 1.9 port note wikitext text/x-wiki {{Toolinfo |name=Custom Regions Support |type=Core dependency mod |authors=Garrakx, Slime_Cubed, Henpemaz |maintainers=Garrakx |status=Supported |releases=[https://github.com/Garrakx/Custom-Regions GitHub] }} {{Cleanup}} {{Legacy}} '''Custom Regions Support''' or '''CRS''' is a library/util mod that was created as an easier way to install [[Content Mods]], replacing file merging. It allows to install multiple region mods at once easily, quickly toggle them, and makes region development less messy. '''Custom Regions Support is in the process of being ported to Rain World 1.9.''' As of now, it is the primary way of installing any and all custom regions, and many of them are ''CRS-exclusive''. == Features == === Runtime worldfile merging === ''For basics of region architecture, see [[World File Format]]'' CRS attempts to smartly combine region world files and avoid room connectivity conflicts. It is the most effective if region mods don't distribute full modified copies of WORLD_XX.txt files for conflict-prone connection (such as vanilla region's WORLD_XX, when a modded region connects to it), and instead ''only include lines that need to be changed or added''. This is commonly referred to as "refining worldfiles". In addition to connection files, it can also merge region property files. === In-game downloader === CRS config menu allows the user to install most region packs from inside the game in one click, including their dependency DLLs, and also quickly toggle installed packs on and off. Downloader menu is reshuffled every day to give every CRS-published region a shot. === Region-conditional connections === Connections may be toggled depending on if a certain region is present: <pre> ROOMS (TM, !BL)roomA : roomB, roomD //only used if TM is installed and BL is not ENDROOMS </pre> This can be combined with unused vanilla behaviour of character-specific connections. === Connection fixer === Starting with v0.9.xx, CRS can attempt to fix some broken connections. This behaviour isn't a catchall but can make some conflicts less lethal. === Additional asset loading === CRS allows easily loading assets commonly bundled with most regions, such as music files, region splash art for passage/regions map screens, decals etc. === Misc === * Making previously hardcoded settings (electric gates, albino colouring on creatures, chance of salamander colouring etc) configurable with json files * Removing creature spawns * No-code addition of custom pearls * Adding unlockable arenas 2b1106e27e522b3cbc9204136903c15f61229541 Main Page 0 1 445 414 2023-04-04T13:40:16Z Cashewww 2 tweaked some wording wikitext text/x-wiki __NOTOC__ [[File:RWModdingTitle.png|750px|frameless|center]] <br> <div id="intro-text" style="text-align: center;"> '''Welcome!''' The Rain World Modding Wiki is a place to share information about modding the video game, ''Rain World''. For more about the game, check out the '''[https://rainworld.miraheze.org/wiki/Rain_World_Wiki Official Rain World Wiki]'''! To get involved, be sure to check out the modding category in the [https://discord.gg/rainworld Rain World Discord]. </div> == Where to Start... == Starting with game version 1.9 (Remix update), mods are installed through Steam Workshop and toggled through in-game Remix menu. If you want to install these mods on a non-Steam copy of the game, see [[Remix Mods Outside of Steam]]. If you want to install mods for a legacy game version (1.5 and below), see [[Legacy Mod Installation]]. For description of architecture changes due to the release of Downpour, as well as technical reference for Remix (the built-in modloader), see [[Downpour Reference]]. On a technical level, most mods can be split into the following families: * [[:Category:Code Mods|Code Mods]] (any mod where the main component is a .dll file) * [[:Category:Content Mods|Content Mods]] (this includes region packs, arenas, etc.). Follow one of the links above to learn more about making these kinds of mods. Sometimes there is overlap. For example a [[Custom Region Support|region pack]] (a type of content mod) may require additional code mods for custom creatures, or a code mod may require additional asset files (though often they are embedded within the dll). If you have questions that the wiki can't yet answer, feel free to ask in the modding category in the [https://discord.gg/rainworld Rain World Discord]. == Contributing == If you have modding knowledge that the wiki doesn't yet have, please do contribute! The following categories contain pages demanding attention: * [[:Category:Cleanup needed]] * [[:Category:Unfinished]] Don't forget to check [[Contribution Guidelines]]. == Quick Links == * [[:Category:Code Mods]] * [[:Category:Content Mods]] * [[:Category:Dev Tools]] * [[:Category:Dependencies]] * [[:Category:Utilities and Tools]] * [[CRS]] * [[Warp]] 3dc79d5f3037e89a0af4667b45687803419fc86e Warp 0 128 446 374 2023-04-04T13:42:50Z Cashewww 2 updated warp installation instructions wikitext text/x-wiki Warp is a utility mod for Rain World that you can use to easily teleport to different rooms and regions. It is particularly useful for testing mods and [[CRS|region packs]]. Download and install Warp by subscribing from Steam Workshop, or download from [https://www.raindb.net/ RainDB] or [https://github.com/LeeMoriya/Warp/releases/latest Warp's GitHub page] and follow the instructions for [[Remix Mods Outside of Steam]]. == Usage == [[File:WarpMenu.png|thumb|Region buttons are shown on the left, room buttons are shown on the right. There are also settings for different colour codings and order schemes. ]] Install Warp using [[BepInEx]], and then Warp menu will appear in the in-game pause menu. Clicking on a room button will teleport the player to the room's first entrance pipe (numbered 0). Clicking on a region button (other than the one the player is currently in) will load the region and show a list of its rooms instead. The loading process may take a few seconds if the region is particularly large. === Issues When Warping === If the region doesn't load then there is likely an issue with the region or room you are trying to warp to. Check your [[Logs|exceptionLog]] for errors and review any recent changes you made to the region/rooms. If you are making a custom region, make sure there are no errors with room connections in your World file, or problems with your room's geometry (e.g. invalid pipe entrances). If you have installed/uninstalled a new region, make sure you have started the game from a fresh save since that region was added or the game may freeze when switching regions or resting in a shelter. == Custom Den Position == Warp features and option to change which room the game considers as the player's den position (the room in which they start the next cycle). Note that if you're using [[Extended Dev Tools]], the 'Start Map' parameter in the <code>edtSetup.json</code> must be empty or it will override Warp. * Hold Shift and click a room name to set the den position. * Press C to reset the den position to its default. == Custom Regions Support == Warp supports [[CRS|Garrakx's Custom Regions Support]] mod which allows for easier creation of new regions and region changes, and will load new rooms from within your CustomResources folder. Below is how room lists are currently generated: === Current Region === The list of rooms for the region you are currently in are taken directly from the list of loaded AbstractRooms. === Different Regions === When you click on a button for a different region, the room list is generated like so: # Rooms are added to the room list from the vanilla World folder. # Each Rooms folder found in CustomResources is scanned and rooms not already in the list are added. At the moment, this means that if a region pack is present in your CustomResources folder but has been manually disabled in its regionInfo.json, rooms from this folder will be regardless and clicking on them will do nothing. This is also technically the case for any region pack that removes rooms. [[Category:Utilities and Tools]] b13cdc123ed62b565472b01752212c880521ca56 Remix Mods Outside of Steam 0 178 447 413 2023-04-04T13:47:52Z Thalber 3 add raindb link wikitext text/x-wiki {{Cleanup}} Mods are typically distributed through Steam Workshop. However, since the game is also sold on other platforms, some people with a legitimate copy may be unable to access mods normally. We'll ''hope'' you are one of those. == Which mods can I install manually? == [https://www.raindb.net/ RainDB] now acts as a Workshop mirror with direct download links. === If a mod is not on RainDB for some reason === To our knowledge, it is against Steam TOS to download workshop items for games you don't have. You have two options: * Some authors provide non-Workshop download links in mod descriptions (usually hosted on GitHub). * If there isn't a direct download link, you can instead ask someone with a Steam copy of the game to download the mod and send you the files. Workshop items are downloaded into subfolders <code>[steamlibrary]/steamapps/workshop/content/312520</code> ('''312520''' is Rain World's steam appid). Subfolders are named by workshop item ID. == How do I install these mods? == [[File:RemixModFolder.png|thumb|Image of correctly placed Remix mod main folder.]] You take the files and put them into <code>[Rain World]/RainWorld_Data/StreamingAssets/mods</code> so that <code>modinfo.json</code> is directly in a subfolder. Exact <code>mods</code> subfolder names do not matter, but it is a good idea to call them something sensible regardless. Done, your mod should appear in Remix menu, be toggleable and work as normal. 80c58cdd989c74a86e2b54c9e5fbbedc8684e692 Rain World Code Structure/ProcessManager and Subprocesses 0 189 448 2023-04-04T14:29:03Z Thalber 3 init wikitext text/x-wiki {{todo|target=article}} == ProcessManager == This is another singleton class contained inside the [[../RainWorld|RainWorld]] singleton. It manages switching different general components of the game, such as main menu, game session, music player etc. ProcessManager passes update calls to subprocesses. {| class="wikitable sortable" |+ Notable members |- ! Name !! Kind !! Description |- | RainWorld || field || Reference to RainWorld holding the instance |- | CurrentMainLoop || field || Subprocess that is currently focused. If the game is in main menu, it is a menu subprocess; if the game is in session, it's a game session, etc |- | sideProcesses || field || All subprocesses that are not currently focused. For example, if the game is in session but paused, game session subprocess is in there |- | upcomingProcess || field || When subprocesses are being switched with a fade transition, upcoming one is stored in this field |- | MusicPlayer || field || Special subprocess that manages music track playback. Null if music volume is set to zero in options |- | StopSideProcess || method || Shuts down and deletes a selected subprocess |- | Update || method || Passes update call from RainWorld to all subprocesses |- | RequestMainProcessSwitch || method || (overloaded) Requests for ProcessManager to create a new subprocess and switch to it, with a fade transition |} == MainLoopProcess == This is the base class for all subprocesses. {| class="wikitable sortable" |+ Notable members |- ! Name !! Kind !! Description |- | manager || field || Reference to owning ProcessManager |- | ID || field || This process' ID extenum |- | framesPerSecond || field || Target FPS for the process. Some processes change this to speed up or slow down their behavior |- | processActive || field || Indicates whether the process is |- | RawUpdate || method || Update method called at max FPS (usually capped at 60). Attempts to call Update at a stable rate of <code>framesPerSecond</code> |- | Update || method || Update method that the process attempts to call at a stable rate of <code>framesPerSecond</code> |} Child classes: === RainWorldGame === Holds any actual game session, arena or campaign. {| class="wikitable sortable" |+ Notable members |- ! Name !! Kind !! Description |- | clock || field || Counter that increments every physics frame; used to track how much time has passed since beginning of the cycle |- | globalRain || field || GlobalRain object that coordinates rain game over. Null until cycle time runs out |- | paused || field || Whether the session is currently paused |- | cameras || property || An array of RoomCamera objects in current game. Length is always 1 in vanilla |- | world || property || [[../World|World]] object, containing currently loaded region |- | Players || property || A list of [[../LOD|AbstractCreature]] objects for player-controlled slugcats |- | session || field || Current GameSession object. May be either ArenaGameSession or StoryGameSession |- | IsArenaSession || property || Checks whether session is arena mode |- | GetArenaGameSession || property || Casts session to ArenaGameSession (throws an error if not arena) |- | IsStorySession || property || Checks whether session is story mode |- | GetStoryGameSession || property || Casts session to StoryGameSession (throws an error if not story) |- | StoryCharacter || property || Returns current story slugcat name, null if arena |- | GetNewID || method || Returns a new unique [[../LOD|AbstractWorldEntity]] ID |} === Menu.MusicPlayer === {{todo}} Handles music playback that persists even when processes are switched. Always exists, as long as music is not disabled in options. === RainWorldSteamManager === Game's proxy class for interacting with Steam API (mostly for achievements). === MenuMicrophone === Handles menu sfx{{Cn}}. === Menu.Menu === {{todo}} Base class for multiple menu processes, such as tutorial tips, config screens, and dating sim. a3a4e63ce52fa9b10cb1c723651e5f23d8da39ec Template:Cn 10 153 452 306 2023-04-05T15:11:05Z Thalber 3 Make it shorter wikitext text/x-wiki <includeonly>[[Category:Verification_Needed]]<small><sup>[[:Category:Verification_Needed|[{{{1|verify}}}]]]</sup></small></includeonly><noinclude> Denotes a statement for future validity check. == Usage == <code><nowiki>Every dog has 6 legs{{Cn}}</nowiki></code> Every dog has 6 legs{{Cn}} <code><nowiki>Every dog has 6 legs{{Cn|what?}}</nowiki></code> Every dog has 6 legs{{Cn|what?}} </noinclude> e83b853657e5965622e31f19340409604f18a60e Rain World Code Structure/GameSession 0 190 453 2023-04-05T15:35:51Z Thalber 3 init wikitext text/x-wiki {{Cleanup}} GameSession is a class held by a [[../ProcessManager_and_Subprocesses#MainLoopProcess|RainWorldGame]]. It holds specific game rules of the current session (be that arena or campaign). Class is abstract. {| class="wikitable sortable" |+ Common members |- ! Name !! Kind !! Description |- | characterStats || field || Object containing default character stats for playable slugcats |- | creatureCommunities || field || Object containing regional and global reputation values |- | difficulty || field || Dynamic difficulty, affects some creature reputation checks |- | game || field || Reference back to [[../ProcessManager_and_Subprocesses#MainLoopProcess|RainWorldGame]] |- | Players || field || List of player characters in the game |} '''IMPORTANT''': many parts in vanilla code check whether current session is StoryGameSession or ArenaGameSession and make assumptions based on that. Child classes: == StoryGameSession == Campaign sitting. {| class="wikitable sortable" |+ Useful members |- ! Name !! Kind !! Description |- | saveStateNumber || field || Current campaign character |- | saveState || field || [[../Save_Data|SaveState]] object containing information about campaign progression |- | characterStatsJollyplayer || field || Character stats for multiple players |} == ArenaGameSession == Arena sitting. Always works with a single-room world. Arena sessions contain one or more <code>ArenaBehaviors.ArenaGameBehavior</code>s. These modify arena rules. <!-- {| class="wikitable" |+ Arena behaviors |- ! Type !! Function |- | ArenaBehaviors.ChallengeBehavior || Used for challenge mode to track win/failure states |- | ArenaBehaviors.EarlyRain || Triggers rain when there is only one player left |- | ArenaBehaviors.Evilifier || Maxes out creature aggression{{Cn}} |- | ArenaBehaviors.ExitManager || Controls when players are allowed to exit the arena{{Cn}} |- | ArenaBehaviors.NoRain || Removes rain |- | ArenaBehaviors.RespawnFlies || Respawns batflies |- | ArenaBehaviors.SandboxEditor || Manages sandbox spawn edit menu |- | ArenaBehaviors.StartBump || Plays a sound and displays arena or challenge name |} --> {| class="wikitable sortable" |+ Useful members |- ! Name !! Kind !! Description |- | IsCreatureAllowedToEmergeFromDen || method || Checks whether a given creature can enter the arena |- | AddBehavior || method || Registers a specified Arenabehaviors.ArenaBehavior |- | RemoveBehavior || method || Removes a specified Arenabehaviors.ArenaBehavior |- | ScoreOfPlayer || method || Returns current score of given player |- | room || property || The one and only arena room |- | arenaSitting || field || An object that carries information about current playlist of arenas (if there is one) |- | behaviors || field || A list of active behaviors |} ArenaGameSession is abstract and has children SandboxGameSession and CompetitiveGameSession. These do not contain any specific members worth listing here. 5a489ebcce5c0629047c8b6e11dc6131b1429d2e File:Fadepalette example.png 6 191 454 2023-04-05T17:43:14Z Isbjorn52 149 Shows a fade pallete example from pallete 0 to pallete 9 at 0%, 50%, and 100%. wikitext text/x-wiki == Summary == Shows a fade pallete example from pallete 0 to pallete 9 at 0%, 50%, and 100%. 30456831ea069b949ab131b7c2bce49c23472c13 455 454 2023-04-05T17:50:55Z Isbjorn52 149 Isbjorn52 uploaded a new version of [[File:Fadepalette example.png]] wikitext text/x-wiki == Summary == Shows a fade pallete example from pallete 0 to pallete 9 at 0%, 50%, and 100%. 30456831ea069b949ab131b7c2bce49c23472c13 457 455 2023-04-05T19:39:54Z Isbjorn52 149 Isbjorn52 uploaded a new version of [[File:Fadepalette example.png]] wikitext text/x-wiki == Summary == Shows a fade pallete example from pallete 0 to pallete 9 at 0%, 50%, and 100%. 30456831ea069b949ab131b7c2bce49c23472c13 Dev Tools 0 84 456 333 2023-04-05T17:52:07Z Isbjorn52 149 wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. A tip for expanding functionality can be found on the [[DebugMouse]] page. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ==Interface Tabs== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. <div class="wikitable"><tabber> |-| Room settings= This tab mostly contains settings for base room visuals, such as palette, cloud cover and terrain wetness. === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === [[File:Fadepalette example.png]] ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image above shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! {|class="wikitable" |- ! '''Effect''' !! '''Description''' !! '''Showcase''' |- | SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. || [[File:Effect 1.png|frameless|The effect at 100%]] |- | SkyBloom || Increases how fuzzy/bloomy the sky's light is. || [[File:Effect 2.png|frameless|Applying the effect]] |- | LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. || [[File:Effect 3.png|frameless]] |- | SkyAndLightBloom || A mix between skybloom and light burn at the same time is more intense. || [[File:Effect 4.gif|frameless|Applying the effect]] |- | Bloom || Similar to SkyBloom, but applies to lights. || [[File:Effect 5.png|frameless]] |- | Fog || Creates a white cloudy effect at layer 1. Not compatible with SkyBloom, LightBurn, SkyAndLightBloom and Bloom. || [[File:Effect 6.png|frameless]] |- | Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- |- | GreenSparks || Underhang, and the Legs' green sparkles. |- | VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | Flies || Spawns small flys that buzz around the room and land on objects. |- | FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | TinyDragonFly || Spawns tiny bugs that fly around plants. |- | RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | Ant || Spawns small jumping bugs. |- | Beetle || Spawns small beetles that slowly fly around the room. |- | WaterGlowWorm || Spawns small worms that swim around in water. |- | Wasp || Spawns small wasps that quickly dart between walls. |- | Moth || Spawns small white moths which slowly flutter around the room. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom, VoidMelt </syntaxhighlight> |-| Objects= Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds= [[File:soundTab.png|400px|right|border|]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map= {{todo|target=tab}} [[File:mapTab.png|400px|right|border|]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections.png|400px|right|border|Connections on dev map]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png|400px|right|border|Canon view of the map]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png|400px|right|border|Example of a rendered map .png file]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers= {{todo|target=tab}} [[File:triggerTab.png|600px|right|border|Trigger tab view]] <span id="general-controls"></span> == General controls == === Save === Saves the current effects and room settings to a file inside the region’s World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by pressing R and returning to the room to see the changes. === Inherent from template === Will set the values stored in a specific template the region has to this room. === Save as template: === Saves the current room’s settings as a template for easy re-use. == Triggers Menu == '''Triggers''' are the mechanism in which some in-game events occur, such as specific songs playing, projections being displayed by the player guide overseer, or information text being displayed at the bottom of the screen. Clicking one of the four options in the bottom right-hand box will place a trigger of that type, which can be moved just like other devtools objects. === Trigger Options === Triggers have a number of settings which determine what the trigger does and under what circumstances. {| class="wikitable" |+ |- ! Trigger setting !! Description |- | Active from cycle || The minimum total cycle requirement for the trigger to activate. |- | Active up to cycle || The maximum cycle limit for the trigger to activate - if the player has a cycle count higher than this number, the trigger will not activate. |- | Fire chance || A random percentage chance for the trigger to activate, from 0% to 100%. |- | Trigger delay || How many seconds between the requirements for the trigger being met and the event occurring. |- | Karma req || The minimum karma the player needs for the trigger to activate (from 0 to 5) |- | Can only fire once/Can fire multiple times || Self-explanatory, determines whether the trigger only fires once or not. |- | No entrance requirement/Entrance XX || Determines whether the player can enter from any entrance pipe, or whether they need to come through a specific one. When an entrance is selected, a red line will connect this entrance and the options box. |- | White, Yellow, Red || Determines which gamemodes the trigger fires on - Survivor, Hunter or Monk. A gamemode’s name being displayed means that the trigger will fire in said gamemode. |} === Event Types === The lowest button on the options box lets you pick what type of event you want to add. ==== MusicEvent ==== Plays a song from the soundtrack. * The first button lets you pick the song you want to play. Files for these songs can be found in *Rain World, or many of them can be found [https://www.youtube.com/playlist?list=PLPJWSVeszYFBo1oAXYgzGfJfewnGKgGna online.] {| class="wikitable" |+ MusicEvent options |- ! Option !! Description |- | Play volume || The volume the song plays at. |- | Fade in || In seconds, how long the song takes to reach full volume. |- | Song priority || If this song’s priority is higher than another’s, then this song will continue to play if the other trigger is activated. If the priority is lower, then the higher one will play instead of it. |- | Drone volume || WIP, presumably adds a background drone sound at the set volume. |- | Fade out at threat || The threat level at which the song fades out and is overtaken by the threat music. |- | Rest cycles || If this trigger can activate multiple times, the number of cycles for the trigger to wait before being able to fire again. |- | Room transitions || How many rooms the song will continue playing through. |- | One song per cycle || Whether or not the same song can activate multiple times in one cycle. |- | Play once/loop || Determines whether the song plays once or loops |- | Continue at death || Continue playing the song when the player dies. |- | Continue through gate || Continue playing the song when the player uses a region gate. |} ==== StopMusicEvent ==== As the name says, stops one or more MusicEvents. The first button lets you pick the song you want to stop/exclude. * '''Priority:''' If a song has a higher priority than the trigger, it won’t stop. * '''Fade out:''' Same as fade in, but fading out to silence. * '''Stop all songs/stop specific song/stop all but specific song:''' Self-explanatory, song selected at the top of the box is what this refers to. ==== '''PoleMimicSubtleReveal''' ==== Causes a pole mimic to flutter slightly when activated. ==== '''ShowProjectedImageEvent''' ==== Shows player guide overseer projections ==== '''RoomSpecificTextMessage''' ==== Causes specific text prompt to appear. Prompts are hardcoded by room name {{Cn}} ==== '''BringPlayerGuideToRoom''' ==== Forces player overseer to current room === Trigger Types === * '''Spot:''' The most commonly used trigger; activates when slugcat walks into a specific circular area of the room. This is indicated by a white area-of-effect which can be moved and scaled. * '''SeeCreature:''' ''WIP, presumably activates upon a certain creature being seen.'' * '''RegionBump:''' Activates either when the region is entered or at the beginning of a cycle where the region name and cycle count is shown. * '''PreRegionBump:''' Seemingly functions the same way as RegionBump. </tabber> </div> [[Category:Dev Tools]] c0cf02eeada4dd88e3d35827583ad9d25cf1a62b 458 456 2023-04-05T19:44:08Z Isbjorn52 149 wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. A tip for expanding functionality can be found on the [[DebugMouse]] page. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ==Interface Tabs== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. <div class="wikitable"><tabber> |-| Room settings= This tab mostly contains settings for base room visuals, such as palette, cloud cover and terrain wetness. === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image below shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} [[File:Fadepalette example.png|1440px]] ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! {|class="wikitable" |- ! '''Effect''' !! '''Description''' !! '''Showcase''' |- | SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. || [[File:Effect 1.png|frameless|The effect at 100%]] |- | SkyBloom || Increases how fuzzy/bloomy the sky's light is. || [[File:Effect 2.png|frameless|Applying the effect]] |- | LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. || [[File:Effect 3.png|frameless]] |- | SkyAndLightBloom || A mix between skybloom and light burn at the same time is more intense. || [[File:Effect 4.gif|frameless|Applying the effect]] |- | Bloom || Similar to SkyBloom, but applies to lights. || [[File:Effect 5.png|frameless]] |- | Fog || Creates a white cloudy effect at layer 1. Not compatible with SkyBloom, LightBurn, SkyAndLightBloom and Bloom. || [[File:Effect 6.png|frameless]] |- | Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- |- | GreenSparks || Underhang, and the Legs' green sparkles. |- | VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | Flies || Spawns small flys that buzz around the room and land on objects. |- | FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | TinyDragonFly || Spawns tiny bugs that fly around plants. |- | RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | Ant || Spawns small jumping bugs. |- | Beetle || Spawns small beetles that slowly fly around the room. |- | WaterGlowWorm || Spawns small worms that swim around in water. |- | Wasp || Spawns small wasps that quickly dart between walls. |- | Moth || Spawns small white moths which slowly flutter around the room. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom, VoidMelt </syntaxhighlight> |-| Objects= Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds= [[File:soundTab.png|400px|right|border|]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map= {{todo|target=tab}} [[File:mapTab.png|400px|right|border|]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections.png|400px|right|border|Connections on dev map]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png|400px|right|border|Canon view of the map]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png|400px|right|border|Example of a rendered map .png file]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers= {{todo|target=tab}} [[File:triggerTab.png|600px|right|border|Trigger tab view]] <span id="general-controls"></span> == General controls == === Save === Saves the current effects and room settings to a file inside the region’s World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by pressing R and returning to the room to see the changes. === Inherent from template === Will set the values stored in a specific template the region has to this room. === Save as template: === Saves the current room’s settings as a template for easy re-use. == Triggers Menu == '''Triggers''' are the mechanism in which some in-game events occur, such as specific songs playing, projections being displayed by the player guide overseer, or information text being displayed at the bottom of the screen. Clicking one of the four options in the bottom right-hand box will place a trigger of that type, which can be moved just like other devtools objects. === Trigger Options === Triggers have a number of settings which determine what the trigger does and under what circumstances. {| class="wikitable" |+ |- ! Trigger setting !! Description |- | Active from cycle || The minimum total cycle requirement for the trigger to activate. |- | Active up to cycle || The maximum cycle limit for the trigger to activate - if the player has a cycle count higher than this number, the trigger will not activate. |- | Fire chance || A random percentage chance for the trigger to activate, from 0% to 100%. |- | Trigger delay || How many seconds between the requirements for the trigger being met and the event occurring. |- | Karma req || The minimum karma the player needs for the trigger to activate (from 0 to 5) |- | Can only fire once/Can fire multiple times || Self-explanatory, determines whether the trigger only fires once or not. |- | No entrance requirement/Entrance XX || Determines whether the player can enter from any entrance pipe, or whether they need to come through a specific one. When an entrance is selected, a red line will connect this entrance and the options box. |- | White, Yellow, Red || Determines which gamemodes the trigger fires on - Survivor, Hunter or Monk. A gamemode’s name being displayed means that the trigger will fire in said gamemode. |} === Event Types === The lowest button on the options box lets you pick what type of event you want to add. ==== MusicEvent ==== Plays a song from the soundtrack. * The first button lets you pick the song you want to play. Files for these songs can be found in *Rain World, or many of them can be found [https://www.youtube.com/playlist?list=PLPJWSVeszYFBo1oAXYgzGfJfewnGKgGna online.] {| class="wikitable" |+ MusicEvent options |- ! Option !! Description |- | Play volume || The volume the song plays at. |- | Fade in || In seconds, how long the song takes to reach full volume. |- | Song priority || If this song’s priority is higher than another’s, then this song will continue to play if the other trigger is activated. If the priority is lower, then the higher one will play instead of it. |- | Drone volume || WIP, presumably adds a background drone sound at the set volume. |- | Fade out at threat || The threat level at which the song fades out and is overtaken by the threat music. |- | Rest cycles || If this trigger can activate multiple times, the number of cycles for the trigger to wait before being able to fire again. |- | Room transitions || How many rooms the song will continue playing through. |- | One song per cycle || Whether or not the same song can activate multiple times in one cycle. |- | Play once/loop || Determines whether the song plays once or loops |- | Continue at death || Continue playing the song when the player dies. |- | Continue through gate || Continue playing the song when the player uses a region gate. |} ==== StopMusicEvent ==== As the name says, stops one or more MusicEvents. The first button lets you pick the song you want to stop/exclude. * '''Priority:''' If a song has a higher priority than the trigger, it won’t stop. * '''Fade out:''' Same as fade in, but fading out to silence. * '''Stop all songs/stop specific song/stop all but specific song:''' Self-explanatory, song selected at the top of the box is what this refers to. ==== '''PoleMimicSubtleReveal''' ==== Causes a pole mimic to flutter slightly when activated. ==== '''ShowProjectedImageEvent''' ==== Shows player guide overseer projections ==== '''RoomSpecificTextMessage''' ==== Causes specific text prompt to appear. Prompts are hardcoded by room name {{Cn}} ==== '''BringPlayerGuideToRoom''' ==== Forces player overseer to current room === Trigger Types === * '''Spot:''' The most commonly used trigger; activates when slugcat walks into a specific circular area of the room. This is indicated by a white area-of-effect which can be moved and scaled. * '''SeeCreature:''' ''WIP, presumably activates upon a certain creature being seen.'' * '''RegionBump:''' Activates either when the region is entered or at the beginning of a cycle where the region name and cycle count is shown. * '''PreRegionBump:''' Seemingly functions the same way as RegionBump. </tabber> </div> [[Category:Dev Tools]] cb76ce07676a5cbe196df1dfda3a1dc2623ef83d 459 458 2023-04-05T19:47:40Z Isbjorn52 149 wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. A tip for expanding functionality can be found on the [[DebugMouse]] page. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ==Interface Tabs== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. <div class="wikitable"><tabber> |-| Room settings= This tab mostly contains settings for base room visuals, such as palette, cloud cover and terrain wetness. === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image below shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} [[File:Fadepalette example.png|1440px|center|border]] ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! {|class="wikitable" |- ! '''Effect''' !! '''Description''' !! '''Showcase''' |- | SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. || [[File:Effect 1.png|frameless|The effect at 100%]] |- | SkyBloom || Increases how fuzzy/bloomy the sky's light is. || [[File:Effect 2.png|frameless|Applying the effect]] |- | LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. || [[File:Effect 3.png|frameless]] |- | SkyAndLightBloom || A mix between skybloom and light burn at the same time is more intense. || [[File:Effect 4.gif|frameless|Applying the effect]] |- | Bloom || Similar to SkyBloom, but applies to lights. || [[File:Effect 5.png|frameless]] |- | Fog || Creates a white cloudy effect at layer 1. Not compatible with SkyBloom, LightBurn, SkyAndLightBloom and Bloom. || [[File:Effect 6.png|frameless]] |- | Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- |- | GreenSparks || Underhang, and the Legs' green sparkles. |- | VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | Flies || Spawns small flys that buzz around the room and land on objects. |- | FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | TinyDragonFly || Spawns tiny bugs that fly around plants. |- | RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | Ant || Spawns small jumping bugs. |- | Beetle || Spawns small beetles that slowly fly around the room. |- | WaterGlowWorm || Spawns small worms that swim around in water. |- | Wasp || Spawns small wasps that quickly dart between walls. |- | Moth || Spawns small white moths which slowly flutter around the room. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom, VoidMelt </syntaxhighlight> |-| Objects= Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds= [[File:soundTab.png|400px|right|border|]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map= {{todo|target=tab}} [[File:mapTab.png|400px|right|border|]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections.png|400px|right|border|Connections on dev map]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png|400px|right|border|Canon view of the map]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png|400px|right|border|Example of a rendered map .png file]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers= {{todo|target=tab}} [[File:triggerTab.png|600px|right|border|Trigger tab view]] <span id="general-controls"></span> == General controls == === Save === Saves the current effects and room settings to a file inside the region’s World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by pressing R and returning to the room to see the changes. === Inherent from template === Will set the values stored in a specific template the region has to this room. === Save as template: === Saves the current room’s settings as a template for easy re-use. == Triggers Menu == '''Triggers''' are the mechanism in which some in-game events occur, such as specific songs playing, projections being displayed by the player guide overseer, or information text being displayed at the bottom of the screen. Clicking one of the four options in the bottom right-hand box will place a trigger of that type, which can be moved just like other devtools objects. === Trigger Options === Triggers have a number of settings which determine what the trigger does and under what circumstances. {| class="wikitable" |+ |- ! Trigger setting !! Description |- | Active from cycle || The minimum total cycle requirement for the trigger to activate. |- | Active up to cycle || The maximum cycle limit for the trigger to activate - if the player has a cycle count higher than this number, the trigger will not activate. |- | Fire chance || A random percentage chance for the trigger to activate, from 0% to 100%. |- | Trigger delay || How many seconds between the requirements for the trigger being met and the event occurring. |- | Karma req || The minimum karma the player needs for the trigger to activate (from 0 to 5) |- | Can only fire once/Can fire multiple times || Self-explanatory, determines whether the trigger only fires once or not. |- | No entrance requirement/Entrance XX || Determines whether the player can enter from any entrance pipe, or whether they need to come through a specific one. When an entrance is selected, a red line will connect this entrance and the options box. |- | White, Yellow, Red || Determines which gamemodes the trigger fires on - Survivor, Hunter or Monk. A gamemode’s name being displayed means that the trigger will fire in said gamemode. |} === Event Types === The lowest button on the options box lets you pick what type of event you want to add. ==== MusicEvent ==== Plays a song from the soundtrack. * The first button lets you pick the song you want to play. Files for these songs can be found in *Rain World, or many of them can be found [https://www.youtube.com/playlist?list=PLPJWSVeszYFBo1oAXYgzGfJfewnGKgGna online.] {| class="wikitable" |+ MusicEvent options |- ! Option !! Description |- | Play volume || The volume the song plays at. |- | Fade in || In seconds, how long the song takes to reach full volume. |- | Song priority || If this song’s priority is higher than another’s, then this song will continue to play if the other trigger is activated. If the priority is lower, then the higher one will play instead of it. |- | Drone volume || WIP, presumably adds a background drone sound at the set volume. |- | Fade out at threat || The threat level at which the song fades out and is overtaken by the threat music. |- | Rest cycles || If this trigger can activate multiple times, the number of cycles for the trigger to wait before being able to fire again. |- | Room transitions || How many rooms the song will continue playing through. |- | One song per cycle || Whether or not the same song can activate multiple times in one cycle. |- | Play once/loop || Determines whether the song plays once or loops |- | Continue at death || Continue playing the song when the player dies. |- | Continue through gate || Continue playing the song when the player uses a region gate. |} ==== StopMusicEvent ==== As the name says, stops one or more MusicEvents. The first button lets you pick the song you want to stop/exclude. * '''Priority:''' If a song has a higher priority than the trigger, it won’t stop. * '''Fade out:''' Same as fade in, but fading out to silence. * '''Stop all songs/stop specific song/stop all but specific song:''' Self-explanatory, song selected at the top of the box is what this refers to. ==== '''PoleMimicSubtleReveal''' ==== Causes a pole mimic to flutter slightly when activated. ==== '''ShowProjectedImageEvent''' ==== Shows player guide overseer projections ==== '''RoomSpecificTextMessage''' ==== Causes specific text prompt to appear. Prompts are hardcoded by room name {{Cn}} ==== '''BringPlayerGuideToRoom''' ==== Forces player overseer to current room === Trigger Types === * '''Spot:''' The most commonly used trigger; activates when slugcat walks into a specific circular area of the room. This is indicated by a white area-of-effect which can be moved and scaled. * '''SeeCreature:''' ''WIP, presumably activates upon a certain creature being seen.'' * '''RegionBump:''' Activates either when the region is entered or at the beginning of a cycle where the region name and cycle count is shown. * '''PreRegionBump:''' Seemingly functions the same way as RegionBump. </tabber> </div> [[Category:Dev Tools]] f8a4d9bda1e1b36e97f3fed6b080df695ec1013c 460 459 2023-04-05T23:13:20Z Bro748 31 /* Interface Tabs */ wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. A tip for expanding functionality can be found on the [[DebugMouse]] page. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ==Interface Tabs== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. <div class="wikitable"><tabber> |-| Room settings= This tab mostly contains settings for base room visuals, such as palette, cloud cover and terrain wetness. === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image below shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} [[File:Fadepalette example.png|1440px|center|border]] ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! Gameplay Lighting Decorations Insects WaterAndFlooding {|class="wikitable" |- ! '''MSC''' !! '''Effect''' !! '''Description''' !! '''Showcase''' |- !colspan="3"|Gameplay |- | style="color: green;" | No || ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | style="color: green;" | No || BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | style="color: green;" | No || SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | style="color: green;" | No || SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | style="color: green;" | No || ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | style="color: green;" | No || BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | style="color: green;" | No || DayNight || Allows the room to have a night mode. Must be used in tandem with the DayNightSettings object. |- | style="color: red;" | Yes || RoomWrap || Objects and creatures that leave one side of the room will appear on the other side as well. |- | style="color: red;" | Yes || DustWave || Makes a terrifying sandstorm sweep across the room when the rain timer runs out. |- !colspan="3"|Lighting |- | style="color: green;" | No || SkyBloom || Increases how fuzzy/bloomy the sky's light is. || [[File:Effect 2.png|frameless|Applying the effect]] |- | style="color: green;" | No || LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. || [[File:Effect 3.png|frameless]] |- | style="color: green;" | No || SkyAndLightBloom || A mix between skybloom and light burn at the same time is more intense. || [[File:Effect 4.gif|frameless|Applying the effect]] |- | style="color: green;" | No || Bloom || Similar to SkyBloom, but applies to lights. || [[File:Effect 5.png|frameless]] |- | style="color: green;" | No || Fog || Creates a white cloudy effect at layer 1. Not compatible with SkyBloom, LightBurn, SkyAndLightBloom and Bloom. || [[File:Effect 6.png|frameless]] |- | style="color: green;" | No || SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | style="color: green;" | No || ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | style="color: green;" | No || SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- !colspan="3"|Decorations |- | style="color: green;" | No || SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. || [[File:Effect 1.png|frameless|The effect at 100%]] |- | style="color: green;" | No || Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | style="color: green;" | No || BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | style="color: green;" | No || ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- | style="color: green;" | No || GreenSparks || Underhang, and the Legs' green sparkles. |- | style="color: green;" | No || VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | style="color: green;" | No || CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | style="color: green;" | No || AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | style="color: green;" | No || RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | style="color: green;" | No || VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- !colspan="3"|Insects |- | style="color: green;" | No || Flies || Spawns small flys that buzz around the room and land on objects. |- | style="color: green;" | No || FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | style="color: green;" | No || TinyDragonFly || Spawns tiny bugs that fly around plants. |- | style="color: green;" | No || RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | style="color: green;" | No || RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | style="color: green;" | No || Ant || Spawns small jumping bugs. |- | style="color: green;" | No || Beetle || Spawns small beetles that slowly fly around the room. |- | style="color: green;" | No || WaterGlowWorm || Spawns small worms that swim around in water. |- | style="color: green;" | No || Wasp || Spawns small wasps that quickly dart between walls. |- | style="color: green;" | No || Moth || Spawns small white moths which slowly flutter around the room. |- !colspan="3"|WaterAndFlooding |- !colspan="3"|Unsorted |- | style="color: green;" | No || VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom, VoidMelt </syntaxhighlight> |-| Objects= Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds= [[File:soundTab.png|400px|right|border|]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map= {{todo|target=tab}} [[File:mapTab.png|400px|right|border|]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections.png|400px|right|border|Connections on dev map]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png|400px|right|border|Canon view of the map]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png|400px|right|border|Example of a rendered map .png file]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers= {{todo|target=tab}} [[File:triggerTab.png|600px|right|border|Trigger tab view]] <span id="general-controls"></span> == General controls == === Save === Saves the current effects and room settings to a file inside the region’s World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by pressing R and returning to the room to see the changes. === Inherent from template === Will set the values stored in a specific template the region has to this room. === Save as template: === Saves the current room’s settings as a template for easy re-use. == Triggers Menu == '''Triggers''' are the mechanism in which some in-game events occur, such as specific songs playing, projections being displayed by the player guide overseer, or information text being displayed at the bottom of the screen. Clicking one of the four options in the bottom right-hand box will place a trigger of that type, which can be moved just like other devtools objects. === Trigger Options === Triggers have a number of settings which determine what the trigger does and under what circumstances. {| class="wikitable" |+ |- ! Trigger setting !! Description |- | Active from cycle || The minimum total cycle requirement for the trigger to activate. |- | Active up to cycle || The maximum cycle limit for the trigger to activate - if the player has a cycle count higher than this number, the trigger will not activate. |- | Fire chance || A random percentage chance for the trigger to activate, from 0% to 100%. |- | Trigger delay || How many seconds between the requirements for the trigger being met and the event occurring. |- | Karma req || The minimum karma the player needs for the trigger to activate (from 0 to 5) |- | Can only fire once/Can fire multiple times || Self-explanatory, determines whether the trigger only fires once or not. |- | No entrance requirement/Entrance XX || Determines whether the player can enter from any entrance pipe, or whether they need to come through a specific one. When an entrance is selected, a red line will connect this entrance and the options box. |- | White, Yellow, Red || Determines which gamemodes the trigger fires on - Survivor, Hunter or Monk. A gamemode’s name being displayed means that the trigger will fire in said gamemode. |} === Event Types === The lowest button on the options box lets you pick what type of event you want to add. ==== MusicEvent ==== Plays a song from the soundtrack. * The first button lets you pick the song you want to play. Files for these songs can be found in *Rain World, or many of them can be found [https://www.youtube.com/playlist?list=PLPJWSVeszYFBo1oAXYgzGfJfewnGKgGna online.] {| class="wikitable" |+ MusicEvent options |- ! Option !! Description |- | Play volume || The volume the song plays at. |- | Fade in || In seconds, how long the song takes to reach full volume. |- | Song priority || If this song’s priority is higher than another’s, then this song will continue to play if the other trigger is activated. If the priority is lower, then the higher one will play instead of it. |- | Drone volume || WIP, presumably adds a background drone sound at the set volume. |- | Fade out at threat || The threat level at which the song fades out and is overtaken by the threat music. |- | Rest cycles || If this trigger can activate multiple times, the number of cycles for the trigger to wait before being able to fire again. |- | Room transitions || How many rooms the song will continue playing through. |- | One song per cycle || Whether or not the same song can activate multiple times in one cycle. |- | Play once/loop || Determines whether the song plays once or loops |- | Continue at death || Continue playing the song when the player dies. |- | Continue through gate || Continue playing the song when the player uses a region gate. |} ==== StopMusicEvent ==== As the name says, stops one or more MusicEvents. The first button lets you pick the song you want to stop/exclude. * '''Priority:''' If a song has a higher priority than the trigger, it won’t stop. * '''Fade out:''' Same as fade in, but fading out to silence. * '''Stop all songs/stop specific song/stop all but specific song:''' Self-explanatory, song selected at the top of the box is what this refers to. ==== '''PoleMimicSubtleReveal''' ==== Causes a pole mimic to flutter slightly when activated. ==== '''ShowProjectedImageEvent''' ==== Shows player guide overseer projections ==== '''RoomSpecificTextMessage''' ==== Causes specific text prompt to appear. Prompts are hardcoded by room name {{Cn}} ==== '''BringPlayerGuideToRoom''' ==== Forces player overseer to current room === Trigger Types === * '''Spot:''' The most commonly used trigger; activates when slugcat walks into a specific circular area of the room. This is indicated by a white area-of-effect which can be moved and scaled. * '''SeeCreature:''' ''WIP, presumably activates upon a certain creature being seen.'' * '''RegionBump:''' Activates either when the region is entered or at the beginning of a cycle where the region name and cycle count is shown. * '''PreRegionBump:''' Seemingly functions the same way as RegionBump. </tabber> </div> [[Category:Dev Tools]] 5e1b9c15457fa8d7c8069d22779d3848de53f885 461 460 2023-04-06T00:10:34Z Bro748 31 wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. A tip for expanding functionality can be found on the [[DebugMouse]] page. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ==Interface Tabs== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. <div class="wikitable"><tabber> |-| Room settings= This tab mostly contains settings for base room visuals, such as palette, cloud cover and terrain wetness. === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image below shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} [[File:Fadepalette example.png|1440px|center|border]] ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! Gameplay Lighting Decorations Insects WaterAndFlooding {|class="wikitable" |- ! '''MSC''' !! '''Effect''' !! '''Description''' !! '''Showcase''' |- !colspan="3"|Gameplay |- | style="color: green;" | No || ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | style="color: green;" | No || BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | style="color: green;" | No || SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | style="color: green;" | No || SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | style="color: green;" | No || ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | style="color: green;" | No || BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | style="color: green;" | No || DayNight || Allows the room to have a night mode. Must be used in tandem with the DayNightSettings object. |- | style="color: red;" | Yes || RoomWrap || Objects and creatures that leave one side of the room will appear on the other side as well. |- | style="color: red;" | Yes || DustWave || Makes a terrifying sandstorm sweep across the room when the rain timer runs out. |- !colspan="3"|Lighting |- | style="color: green;" | No || SkyBloom || Increases how fuzzy/bloomy the sky's light is. || [[File:Effect 2.png|frameless|Applying the effect]] |- | style="color: green;" | No || LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. || [[File:Effect 3.png|frameless]] |- | style="color: green;" | No || SkyAndLightBloom || A mix between skybloom and light burn at the same time is more intense. || [[File:Effect 4.gif|frameless|Applying the effect]] |- | style="color: green;" | No || Bloom || Similar to SkyBloom, but applies to lights. || [[File:Effect 5.png|frameless]] |- | style="color: green;" | No || Fog || Creates a white cloudy effect at layer 1. Not compatible with SkyBloom, LightBurn, SkyAndLightBloom and Bloom. || [[File:Effect 6.png|frameless]] |- | style="color: green;" | No || SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | style="color: green;" | No || ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | style="color: green;" | No || SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | style="color: green;" | No || Darkness || Darkens the room's palette. |- | style="color: green;" | No || Brightness || Brightens the room's palette. |- | style="color: green;" | No || Contrast || Increases contrast on the room's palette. |- | style="color: green;" | No || Desaturation || Desaturates the room's palette. |- | style="color: green;" | No || Hue || Shifts the hue of the room's palette. |- | style="color: green;" | No || DarkenLights || Darkens the light color on the room's palette. |- | style="color: green;" | No || WaterLights || Changes the visuals of light emitting objects that are underwater. |- !colspan="3"|Decorations |- | style="color: green;" | No || SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. || [[File:Effect 1.png|frameless|The effect at 100%]] |- | style="color: green;" | No || Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | style="color: green;" | No || BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | style="color: green;" | No || ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- | style="color: green;" | No || GreenSparks || Underhang, and the Legs' green sparkles. |- | style="color: green;" | No || VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | style="color: green;" | No || CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | style="color: green;" | No || AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | style="color: green;" | No || RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | style="color: green;" | No || VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | style="color: green;" | No || FairyParticles || Generates screen-wide particles. Should be used in tandem with the FairyParticlesSettings placed object. |- | style="color: green;" | No || Coldness || Causes slugcat to emit cold breath particles. |- | style="color: green;" | No || HeatWave || Applies a heat distortion shader over the room. |- | style="color: green;" | No || DustPuffs || Causes slugcat to emit puffs of dust under their steps. |- | style="color: green;" | No || VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | style="color: red;" | Yes || Advertisements || Overseers will show random advertisement projections. |- !colspan="3"|Insects |- | style="color: green;" | No || Flies || Spawns small flys that buzz around the room and land on objects. |- | style="color: green;" | No || FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | style="color: green;" | No || TinyDragonFly || Spawns tiny bugs that fly around plants. |- | style="color: green;" | No || RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | style="color: green;" | No || RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | style="color: green;" | No || Ant || Spawns small jumping bugs. |- | style="color: green;" | No || Beetle || Spawns small beetles that slowly fly around the room. |- | style="color: green;" | No || WaterGlowWorm || Spawns small worms that swim around in water. |- | style="color: green;" | No || Wasp || Spawns small wasps that quickly dart between walls. |- | style="color: green;" | No || Moth || Spawns small white moths which slowly flutter around the room. |- !colspan="3"|WaterAndFlooding |- | style="color: green;" | No || LightRain || Causes a gentle cosmetic version of death rain to be constantly present. |- | style="color: green;" | No || LightRain || Causes the death rain to be constantly present. Not hard enough to kill, but only to push around. |- | style="color: green;" | No || BulletRain || Causes bullet rain to be constantly present. |- | style="color: green;" | No || BulletRainFlux || Causes bullet rain to fluctuate in intensity and presence. Requires the BulletRain effect. |- | style="color: green;" | No || WaterFluxFrequency || Adjusts how fast water in the room fluctuates. |- | style="color: green;" | No || WaterFluxMinLevel || Adjusts the lowest point the water will descend to. |- | style="color: green;" | No || WaterFluxMaxLevel || Adjusts the highest point the water will rise to. |- | style="color: green;" | No || WaterFluxMinDelay || Adjusts how long the water should pause at the lowest level. |- | style="color: green;" | No || WaterFluxMaxDelay || Adjusts how long the water should pause at the highest level. |- | style="color: green;" | No || WaterFluxSpeed || Adjusts how quickly the water should fluctuate. |- | style="color: green;" | No || WaterFluxOffset || Shifts the WaterFlux cycle to happen later. |- | style="color: green;" | No || WaterFluxRumble || Adjusts how much the room should rumble while the water is fluctuating. |- | style="color: green;" | No || LethalWater || Makes water deadly to anything that touches it. |- | style="color: green;" | No || SilenceWater || Turns off the default ambient water noises. |- | style="color: green;" | No || WaterViscosity || Adjusts how thick the water is. |- | style="color: green;" | No || WaterDepth || Adjusts the visual sublayer the water appears on. Default is sublayer 0 or 1, but this effect allows the water to be placed on any sublayer, even behind the playable area. |- | style="color: red;" | Yes || InvertedWater || Puts water on the ceiling. |- | style="color: green;" | No || DirtyWater || Changes the water's appearance to be more dirty. |- | style="color: red;" | Yes || FastFloodDrain || When precycle flooding is ending, makes the room drain faster. |- | style="color: red;" | Yes || FastFloodPullDown || When precycle flooding is ending, treats the room as if it were lower. |- | style="color: green;" | No || LavaSurface || Changes the water's appearance to be more like lava. |- !colspan="3"|Unsorted |- | style="color: green;" | No || VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom, VoidMelt </syntaxhighlight> |-| Objects= Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds= [[File:soundTab.png|400px|right|border|]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map= {{todo|target=tab}} [[File:mapTab.png|400px|right|border|]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections.png|400px|right|border|Connections on dev map]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png|400px|right|border|Canon view of the map]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png|400px|right|border|Example of a rendered map .png file]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers= {{todo|target=tab}} [[File:triggerTab.png|600px|right|border|Trigger tab view]] <span id="general-controls"></span> == General controls == === Save === Saves the current effects and room settings to a file inside the region’s World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by pressing R and returning to the room to see the changes. === Inherent from template === Will set the values stored in a specific template the region has to this room. === Save as template: === Saves the current room’s settings as a template for easy re-use. == Triggers Menu == '''Triggers''' are the mechanism in which some in-game events occur, such as specific songs playing, projections being displayed by the player guide overseer, or information text being displayed at the bottom of the screen. Clicking one of the four options in the bottom right-hand box will place a trigger of that type, which can be moved just like other devtools objects. === Trigger Options === Triggers have a number of settings which determine what the trigger does and under what circumstances. {| class="wikitable" |+ |- ! Trigger setting !! Description |- | Active from cycle || The minimum total cycle requirement for the trigger to activate. |- | Active up to cycle || The maximum cycle limit for the trigger to activate - if the player has a cycle count higher than this number, the trigger will not activate. |- | Fire chance || A random percentage chance for the trigger to activate, from 0% to 100%. |- | Trigger delay || How many seconds between the requirements for the trigger being met and the event occurring. |- | Karma req || The minimum karma the player needs for the trigger to activate (from 0 to 5) |- | Can only fire once/Can fire multiple times || Self-explanatory, determines whether the trigger only fires once or not. |- | No entrance requirement/Entrance XX || Determines whether the player can enter from any entrance pipe, or whether they need to come through a specific one. When an entrance is selected, a red line will connect this entrance and the options box. |- | White, Yellow, Red || Determines which gamemodes the trigger fires on - Survivor, Hunter or Monk. A gamemode’s name being displayed means that the trigger will fire in said gamemode. |} === Event Types === The lowest button on the options box lets you pick what type of event you want to add. ==== MusicEvent ==== Plays a song from the soundtrack. * The first button lets you pick the song you want to play. Files for these songs can be found in *Rain World, or many of them can be found [https://www.youtube.com/playlist?list=PLPJWSVeszYFBo1oAXYgzGfJfewnGKgGna online.] {| class="wikitable" |+ MusicEvent options |- ! Option !! Description |- | Play volume || The volume the song plays at. |- | Fade in || In seconds, how long the song takes to reach full volume. |- | Song priority || If this song’s priority is higher than another’s, then this song will continue to play if the other trigger is activated. If the priority is lower, then the higher one will play instead of it. |- | Drone volume || WIP, presumably adds a background drone sound at the set volume. |- | Fade out at threat || The threat level at which the song fades out and is overtaken by the threat music. |- | Rest cycles || If this trigger can activate multiple times, the number of cycles for the trigger to wait before being able to fire again. |- | Room transitions || How many rooms the song will continue playing through. |- | One song per cycle || Whether or not the same song can activate multiple times in one cycle. |- | Play once/loop || Determines whether the song plays once or loops |- | Continue at death || Continue playing the song when the player dies. |- | Continue through gate || Continue playing the song when the player uses a region gate. |} ==== StopMusicEvent ==== As the name says, stops one or more MusicEvents. The first button lets you pick the song you want to stop/exclude. * '''Priority:''' If a song has a higher priority than the trigger, it won’t stop. * '''Fade out:''' Same as fade in, but fading out to silence. * '''Stop all songs/stop specific song/stop all but specific song:''' Self-explanatory, song selected at the top of the box is what this refers to. ==== '''PoleMimicSubtleReveal''' ==== Causes a pole mimic to flutter slightly when activated. ==== '''ShowProjectedImageEvent''' ==== Shows player guide overseer projections ==== '''RoomSpecificTextMessage''' ==== Causes specific text prompt to appear. Prompts are hardcoded by room name {{Cn}} ==== '''BringPlayerGuideToRoom''' ==== Forces player overseer to current room === Trigger Types === * '''Spot:''' The most commonly used trigger; activates when slugcat walks into a specific circular area of the room. This is indicated by a white area-of-effect which can be moved and scaled. * '''SeeCreature:''' ''WIP, presumably activates upon a certain creature being seen.'' * '''RegionBump:''' Activates either when the region is entered or at the beginning of a cycle where the region name and cycle count is shown. * '''PreRegionBump:''' Seemingly functions the same way as RegionBump. </tabber> </div> [[Category:Dev Tools]] d72f5df9f5ace72278aa81d3dee4a7a48f32d1c3 462 461 2023-04-06T00:17:13Z Bro748 31 wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. A tip for expanding functionality can be found on the [[DebugMouse]] page. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ==Interface Tabs== Once opening the main dev tools interface with H, the interface is broken up into five different tabs. <div class="wikitable"><tabber> |-| Room settings= This tab mostly contains settings for base room visuals, such as palette, cloud cover and terrain wetness. === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image below shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} [[File:Fadepalette example.png|1440px|center|border]] ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! Gameplay Lighting Decorations Insects WaterAndFlooding {|class="wikitable" |- ! '''MSC''' !! '''Effect''' !! '''Description''' !! '''Showcase''' |- !colspan="3"|Gameplay |- | style="color: green;" | No || ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | style="color: green;" | No || BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | style="color: green;" | No || SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | style="color: green;" | No || SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | style="color: green;" | No || ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | style="color: green;" | No || BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | style="color: green;" | No || DayNight || Allows the room to have a night mode. Must be used in tandem with the DayNightSettings object. |- | style="color: red;" | Yes || RoomWrap || Objects and creatures that leave one side of the room will appear on the other side as well. |- | style="color: red;" | Yes || DustWave || Makes a terrifying sandstorm sweep across the room when the rain timer runs out. |- !colspan="3"|Lighting |- | style="color: green;" | No || SkyBloom || Increases how fuzzy/bloomy the sky's light is. || [[File:Effect 2.png|frameless|Applying the effect]] |- | style="color: green;" | No || LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. || [[File:Effect 3.png|frameless]] |- | style="color: green;" | No || SkyAndLightBloom || A mix between skybloom and light burn at the same time is more intense. || [[File:Effect 4.gif|frameless|Applying the effect]] |- | style="color: green;" | No || Bloom || Similar to SkyBloom, but applies to lights. || [[File:Effect 5.png|frameless]] |- | style="color: green;" | No || Fog || Creates a white cloudy effect at layer 1. Not compatible with SkyBloom, LightBurn, SkyAndLightBloom and Bloom. || [[File:Effect 6.png|frameless]] |- | style="color: green;" | No || SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | style="color: green;" | No || ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | style="color: green;" | No || SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | style="color: green;" | No || Darkness || Darkens the room's palette. |- | style="color: green;" | No || Brightness || Brightens the room's palette. |- | style="color: green;" | No || Contrast || Increases contrast on the room's palette. |- | style="color: green;" | No || Desaturation || Desaturates the room's palette. |- | style="color: green;" | No || Hue || Shifts the hue of the room's palette. |- | style="color: green;" | No || DarkenLights || Darkens the light color on the room's palette. |- | style="color: green;" | No || WaterLights || Changes the visuals of light emitting objects that are underwater. |- !colspan="3"|Decorations |- | style="color: green;" | No || SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. || [[File:Effect 1.png|frameless|The effect at 100%]] |- | style="color: green;" | No || Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | style="color: green;" | No || BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | style="color: green;" | No || ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- | style="color: green;" | No || GreenSparks || Underhang, and the Legs' green sparkles. |- | style="color: green;" | No || VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | style="color: green;" | No || CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | style="color: green;" | No || AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | style="color: green;" | No || RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | style="color: green;" | No || VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | style="color: green;" | No || FairyParticles || Generates screen-wide particles. Should be used in tandem with the FairyParticlesSettings placed object. |- | style="color: green;" | No || Coldness || Causes slugcat to emit cold breath particles. |- | style="color: green;" | No || HeatWave || Applies a heat distortion shader over the room. |- | style="color: green;" | No || DustPuffs || Causes slugcat to emit puffs of dust under their steps. |- | style="color: green;" | No || VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | style="color: red;" | Yes || Advertisements || Overseers will show random advertisement projections. |- !colspan="3"|Insects |- | style="color: green;" | No || Flies || Spawns small flys that buzz around the room and land on objects. |- | style="color: green;" | No || FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | style="color: green;" | No || TinyDragonFly || Spawns tiny bugs that fly around plants. |- | style="color: green;" | No || RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | style="color: green;" | No || RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | style="color: green;" | No || Ant || Spawns small jumping bugs. |- | style="color: green;" | No || Beetle || Spawns small beetles that slowly fly around the room. |- | style="color: green;" | No || WaterGlowWorm || Spawns small worms that swim around in water. |- | style="color: green;" | No || Wasp || Spawns small wasps that quickly dart between walls. |- | style="color: green;" | No || Moth || Spawns small white moths which slowly flutter around the room. |- !colspan="3"|WaterAndFlooding |- | style="color: green;" | No || LightRain || Causes a gentle cosmetic version of death rain to be constantly present. |- | style="color: green;" | No || LightRain || Causes the death rain to be constantly present. Not hard enough to kill, but only to push around. |- | style="color: green;" | No || BulletRain || Causes bullet rain to be constantly present. |- | style="color: green;" | No || BulletRainFlux || Causes bullet rain to fluctuate in intensity and presence. Requires the BulletRain effect. |- | style="color: green;" | No || WaterFluxFrequency || Adjusts how fast water in the room fluctuates. |- | style="color: green;" | No || WaterFluxMinLevel || Adjusts the lowest point the water will descend to. |- | style="color: green;" | No || WaterFluxMaxLevel || Adjusts the highest point the water will rise to. |- | style="color: green;" | No || WaterFluxMinDelay || Adjusts how long the water should pause at the lowest level. |- | style="color: green;" | No || WaterFluxMaxDelay || Adjusts how long the water should pause at the highest level. |- | style="color: green;" | No || WaterFluxSpeed || Adjusts how quickly the water should fluctuate. |- | style="color: green;" | No || WaterFluxOffset || Shifts the WaterFlux cycle to happen later. |- | style="color: green;" | No || WaterFluxRumble || Adjusts how much the room should rumble while the water is fluctuating. |- | style="color: green;" | No || LethalWater || Makes water deadly to anything that touches it. |- | style="color: green;" | No || SilenceWater || Turns off the default ambient water noises. |- | style="color: green;" | No || WaterViscosity || Adjusts how thick the water is. |- | style="color: green;" | No || WaterDepth || Adjusts the visual sublayer the water appears on. Default is sublayer 0 or 1, but this effect allows the water to be placed on any sublayer, even behind the playable area. |- | style="color: red;" | Yes || InvertedWater || Puts water on the ceiling. |- | style="color: green;" | No || DirtyWater || Changes the water's appearance to be more dirty. |- | style="color: red;" | Yes || FastFloodDrain || When precycle flooding is ending, makes the room drain faster. |- | style="color: red;" | Yes || FastFloodPullDown || When precycle flooding is ending, treats the room as if it were lower. |- | style="color: green;" | No || LavaSurface || Changes the water's appearance to be more like lava. |- !colspan="3"|Unsorted |- | style="color: green;" | No || VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | style="color: green;" | No || FakeGate || Adds various dysfunctional visuals to make the room look like a gate. |- | style="color: green;" | No || PixelShift || Moves the camera center when playing in a thinner resolution. Used to keep relevant details on-screen. |- | style="color: red;" | Yes || BrokenPalette || Changes the room's palette to use the 1.5 broken palette. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom, VoidMelt </syntaxhighlight> |-| Objects= Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds= [[File:soundTab.png|400px|right|border|]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map= {{todo|target=tab}} [[File:mapTab.png|400px|right|border|]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections.png|400px|right|border|Connections on dev map]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png|400px|right|border|Canon view of the map]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png|400px|right|border|Example of a rendered map .png file]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers= {{todo|target=tab}} [[File:triggerTab.png|600px|right|border|Trigger tab view]] <span id="general-controls"></span> == General controls == === Save === Saves the current effects and room settings to a file inside the region’s World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by pressing R and returning to the room to see the changes. === Inherent from template === Will set the values stored in a specific template the region has to this room. === Save as template: === Saves the current room’s settings as a template for easy re-use. == Triggers Menu == '''Triggers''' are the mechanism in which some in-game events occur, such as specific songs playing, projections being displayed by the player guide overseer, or information text being displayed at the bottom of the screen. Clicking one of the four options in the bottom right-hand box will place a trigger of that type, which can be moved just like other devtools objects. === Trigger Options === Triggers have a number of settings which determine what the trigger does and under what circumstances. {| class="wikitable" |+ |- ! Trigger setting !! Description |- | Active from cycle || The minimum total cycle requirement for the trigger to activate. |- | Active up to cycle || The maximum cycle limit for the trigger to activate - if the player has a cycle count higher than this number, the trigger will not activate. |- | Fire chance || A random percentage chance for the trigger to activate, from 0% to 100%. |- | Trigger delay || How many seconds between the requirements for the trigger being met and the event occurring. |- | Karma req || The minimum karma the player needs for the trigger to activate (from 0 to 5) |- | Can only fire once/Can fire multiple times || Self-explanatory, determines whether the trigger only fires once or not. |- | No entrance requirement/Entrance XX || Determines whether the player can enter from any entrance pipe, or whether they need to come through a specific one. When an entrance is selected, a red line will connect this entrance and the options box. |- | White, Yellow, Red || Determines which gamemodes the trigger fires on - Survivor, Hunter or Monk. A gamemode’s name being displayed means that the trigger will fire in said gamemode. |} === Event Types === The lowest button on the options box lets you pick what type of event you want to add. ==== MusicEvent ==== Plays a song from the soundtrack. * The first button lets you pick the song you want to play. Files for these songs can be found in *Rain World, or many of them can be found [https://www.youtube.com/playlist?list=PLPJWSVeszYFBo1oAXYgzGfJfewnGKgGna online.] {| class="wikitable" |+ MusicEvent options |- ! Option !! Description |- | Play volume || The volume the song plays at. |- | Fade in || In seconds, how long the song takes to reach full volume. |- | Song priority || If this song’s priority is higher than another’s, then this song will continue to play if the other trigger is activated. If the priority is lower, then the higher one will play instead of it. |- | Drone volume || WIP, presumably adds a background drone sound at the set volume. |- | Fade out at threat || The threat level at which the song fades out and is overtaken by the threat music. |- | Rest cycles || If this trigger can activate multiple times, the number of cycles for the trigger to wait before being able to fire again. |- | Room transitions || How many rooms the song will continue playing through. |- | One song per cycle || Whether or not the same song can activate multiple times in one cycle. |- | Play once/loop || Determines whether the song plays once or loops |- | Continue at death || Continue playing the song when the player dies. |- | Continue through gate || Continue playing the song when the player uses a region gate. |} ==== StopMusicEvent ==== As the name says, stops one or more MusicEvents. The first button lets you pick the song you want to stop/exclude. * '''Priority:''' If a song has a higher priority than the trigger, it won’t stop. * '''Fade out:''' Same as fade in, but fading out to silence. * '''Stop all songs/stop specific song/stop all but specific song:''' Self-explanatory, song selected at the top of the box is what this refers to. ==== '''PoleMimicSubtleReveal''' ==== Causes a pole mimic to flutter slightly when activated. ==== '''ShowProjectedImageEvent''' ==== Shows player guide overseer projections ==== '''RoomSpecificTextMessage''' ==== Causes specific text prompt to appear. Prompts are hardcoded by room name {{Cn}} ==== '''BringPlayerGuideToRoom''' ==== Forces player overseer to current room === Trigger Types === * '''Spot:''' The most commonly used trigger; activates when slugcat walks into a specific circular area of the room. This is indicated by a white area-of-effect which can be moved and scaled. * '''SeeCreature:''' ''WIP, presumably activates upon a certain creature being seen.'' * '''RegionBump:''' Activates either when the region is entered or at the beginning of a cycle where the region name and cycle count is shown. * '''PreRegionBump:''' Seemingly functions the same way as RegionBump. </tabber> </div> [[Category:Dev Tools]] 0b0f6159416477e3daf538aa9a9285603d62fb35 Category:Code Mods 14 74 463 361 2023-04-12T07:27:14Z Thalber 3 wikitext text/x-wiki Code mods are incredibly versatile. They allow for fixing bugs in the vanilla game, adding quality of life (QoL) features, and all sorts of brand new features including new creatures and gamemodes. Code mods are sometimes included in Region Packs, either as supplimentary features or dependencies of those features. To load code mods, we use a modified version of [[BepInEx]]. == Writing Code Mods == Rain World is programmed in C# with Unity, meaning that we have access to plenty of .NET and Unity oriented modding tools. RW code mods are generally written in C# and built for the .NET Framework 4.8 runtime. If you're looking to start making code mods, it's recommended that you start with [[BepInPlugins]]. You're likely to get the most support with these, they're the easiest to make, and they're very capable. Before diving into the details of writing a code mod, you'll need to [[Code Environments|set up your code environment]]. Also, knowing [[Rain World Code Structure]] helps a lot. Modern Rain World code mods typically come in a few flavours... * [[BepInPlugins]] - ''the most common. They largely use a technique called hooking, which allows for many possibilities and makes for good compatibility with other mods.'' * [https://docs.bepinex.dev/articles/dev_guide/preloader_patchers.html Preloader Patchers] - ''powered by Mono.Cecil. Used to apply changes to asseblies during the preloader phase.'' Older Rain World code mods are generally: * [[Standalone Mods]] * [[Partiality Mods]] * [[MonoMod Patches]] 2b232d821b4dab91d6696d3e5f16bf71573b8562 World File Format 0 114 464 349 2023-04-13T14:07:16Z Bro748 31 wikitext text/x-wiki {{Cleanup}} [[File:regionFormat.png|thumb|right|alt=regionFormat|regionFormat]] This page describes worldfile format for RW regions. The world_XX.txt file is present in every region Rain World loads, and determines various room settings such as their pipe connections, the spawns of enemies, and specific flags like shelters and gates. NOTE: Creature spawns for the region are generated when you first enter it on a save. Changing room connections or creature spawns in WORLD_XX after that corrupts save data. '''Reset your saveslot or revert your save to before you entered to avoid bugs'''. == Comments == Worldfile format supports comments: if a line starts with double slash (<code>//</code>), it is ignored entirely. == Room Connections == Room connections section is bounded by <code>ROOMS</code> and <code>END ROOMS</code> tags. These control which pipe entrance leads to what room, and vice versa. Unique room flags that specify certain attributes about the room (such as if it is a shelter or a gate room) are set here as well. The format is as follows: <syntaxhighlight lang="">ROOM : door0, door1, door2, etc : FLAG </syntaxhighlight> === Examples === A standard room with two room-connecting pipes. These will form the bulk of your region. <syntaxhighlight lang="">TR_T07 : TR_T01, TR_P02 </syntaxhighlight> A standard room, with five doors. However, pipes 1, 2 and 3 have no connection. Each pipe inside a room has a specific number starting from 0. These can be viewed using the [[Dev Tools]]' map tab, or by entering the room with dev tools enabled and pressing M. <syntaxhighlight lang="">TR_W19 : TR_L05, DISCONNECTED, DISCONNECTED, DISCONNECTED, TR_W18 </syntaxhighlight> A shelter. These rooms will often be copied from other regions when you are first learning how to make a region. All vanilla save rooms have a single door. <syntaxhighlight lang="">TR_S01 : TR_P01 : SHELTER </syntaxhighlight> A region gate. Doors on the other side of the gate are set to DISCONNECTED. They will automatically be shown as connected doors at runtime. If you need to show a save room door specifically on the other side of the gate, you can use the ExitSymbolShelter object, in the dev tool’s object tab to change the door symbols as required. <syntaxhighlight lang="">GATE_SS_TR : DISCONNECTED, TR_L07 : GATE </syntaxhighlight> A swarm room allows batflies to spawn in the room, as long as the map contains bat nests. If the room has bat nests but is not marked as a swarm room, those nests will always be inactive. The dev tools map tab provides the options needed to control where they will migrate and rooms they will avoid. <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> A scavenger outpost. Use in conjunction with ScavengerOutpost placedObject to create a scavenger toll. <syntaxhighlight lang="">SU_C02 : SU_A45, SU_A07 : SCAVOUTPOST </syntaxhighlight> === Understanding door connections === [[File:regionFormatConnection.png|thumb|none|alt=regionFormatConnection|regionFormatConnection]] For a door to be properly connected, both ends must point to each other using valid doors. For this example, both rooms will have two doors. Door0 will be on the left, and door1 on the right. Door indices are decided specifically for your room, so be sure to check in game how your doors have been assigned by the [[Level Editor]]. The DT Map tab can also be used to see the links between doors. As in the picture to the right. Properly connected doors will show both lines pointing to the set door on the other end. Doors with incorrect links will point off to the bottom right <!--(A disconnected door will also do this,)--> <!--do fucking what--> and a door connected to another room, but that room has no door back (or lacks enough doors!) will point to the center of the room on the map tab page. <syntaxhighlight lang=""> RG_ROOM1 : DISCONNECTED, RG_ROOM2 </syntaxhighlight> <syntaxhighlight lang=""> RG_ROOM2: RG_ROOM1 </syntaxhighlight> Room1 will have its right hand door connected to Room2. Because of this, we need to use DISCONNECTED as a placeholder for its left hand door, door0. Then set door1 to connect to Room2 Room2 will connect to Room1 using door0. Due to this, we do not need to define the right hand door. It will assume it to be disconnected. === Room Tags === Room tags assign certain properties to rooms depending on what the tag is. Tags are assigned like <syntaxhighlight lang=""> [ROOM] : [CONNECTIONS] : [TAG] </syntaxhighlight> Example: <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> {|class="wikitable" !width="18%"| '''<u>Tag</u>''' !width="81%"| '''<u>Function</u>''' |- | SHELTER | Makes the room a shelter. When there are multiple pipes in the room: the animated door is placed at the bottom right most pipe. |- | ANCIENTSHELTER | Makes the room an Outer Expanse style shelter. |- | GATE | Makes the room a gate. Entrances on the other side of the gate are set to DISCONNECTED, and are shown automatically to be connected. |- | SWARMROOM | Allows batflies to be spawned from batfly hives. |- | PERF_HEAVY | Causes the room to be abstractized quicker when player is not inside, can reduce offscreen performance toll of very large rooms. |- | SCAVOUTPOST | Makes the room into a scavenger outpost. Scavs will spawn here and only let you pass if you have a pearl. The exact outpost location is set by the “ScavengerOutpost” devtools object. |- | SCAVTRADER | Spawns a scavenger merchant into the room. Will trade items with you. The merchant is controlled by the “TradeOutpost” devtools object. |- | NOTRACKERS | Disallows key items from saving in the room (for when the 'Key item tracking' Remix setting is turned on) |- | ARENA | Causes creature spawns in the room to stay in their den until activated by an HRGuard (requires MSC!) |} === Important quirks to rooms and doors === When setting up your region, be sure that you always use your region’s prefix to help each room have a unique name. If not, Rain World will treat repeated names as being other rooms, and even re-use rooms from other region folders entirely. If you don’t use your region prefix, changes made with devtools can also wind up getting saved to unexpected places. To avoid these problems, always prefix your room with its region code, and give them unique names. Multiple pipes in a room may all go to the same room. However, these will all act like a single pipe, and you will not be able to set the specific destination pipes. There are no cases in vanilla Rain World where multiple pipes in the current room lead to the same next room. They will all lead to separate rooms. For example, if you had four pipes leading from one room to another. you would need to create a minimum of three unique rooms for each of the other pipes to act as an interconnection. == Creature Spawns == Creature spawn data section is bounded by <code>CREATURES</code> and <code>END CREATURES</code> tags. Rain World only creates creature spawns when you enter a region for the first time on a save<!--, or after an excessive number of cycles has passed--><!--never heard of it before, may be bogus ~thalber-->. {|class="wikitable" !align="center" width="12%"| '''Lizards''' !align="center" width="25%"| '''Insects''' !align="center" width="13%"| '''Amphibians''' !align="center" width="18%"| '''Flying''' !align="center" width="16%"| '''Plants''' !align="center" width="12%"| '''Other''' |- |align="center"| Pink |align="center"| Spider |align="center"| Salamander |align="center"| CicadaA |align="center"| PoleMimic, Mimic* |align="center"| Scavenger |- |align="center"| Green |align="center"| Small Centipede |align="center"| Leech |align="center"| CicadaB |align="center"| Tentacle, TentaclePlant* |align="center"| Lantern Mouse, Mouse* |- |align="center"| Blue |align="center"| Centipede, Centi, Cent* |align="center"| SeaLeech |align="center"| Vulture |align="center"| |align="center"| Worm, Garbage Worm* |- |align="center"| Yellow |align="center"| Red Centipede, RedCenti, RedCentipede* |align="center"| JetFish, Jetfish* |align="center"| KingVulture, King Vulture* |align="center"| |align="center"| Miros, MirosBird* |- |align="center"| White |align="center"| DropBug, Dropbug, DropWig, Dropwig* |align="center"| Snail |align="center"| Needle, Needle Worm* |align="center"| |align="center"| Tube, TubeWorm* |- |align="center"| Black |align="center"| BigSpider |align="center"| Lev, Leviathan |align="center"| SmallNeedleWorm |align="center"| |align="center"| Bro, BroLongLegs* |- |align="center"| Cyan |align="center"| SpitterSpider |align="center"| |align="center"| Centiwing |align="center"| |align="center"| Daddy, DaddyLongLegs* |- |align="center"| Red |align="center"| EggBug, Eggbug* |align="center"| |align="center"| Cicada** |align="center"| |align="center"| |} (*) Interchangeable names (**) Switches between CicadaA and CicadaB) <syntaxhighlight lang=""> //Creature spawns can be specific to a certain character. (0, 1) makes something appear for monk and survivor, (2) only for hunter (character filter)ROOM : PipeNumber-Creature-{optional flags}-Count </syntaxhighlight> === Creature Flags === <!--'Flags' is a bad name for this, I think 'tags' would be more appropriate ~bro--> Creature flags set certain properties of the creature. Any flag can be written to any creature, but it will be ignored if they are not one of the following matches: Lizards may have the {mean:x.x} flag, with x.x representing a number ranging from 0.0 to 1.0 (eg, {Mean:0.6}) This makes the lizard act more aggressively Centipedes may have the {x.x} flag, being a number ranging from 0.0 to 1.0 (eg, {0.7}) This sets the centipede size, with 0.0 being a Small Centipede and 1.0 being an Overgrown Centipede Pole plants may have the {xx} flag, being any non-negative integer (eg, {15}) This sets the length of the pole plant in tiles === Examples === A single green lizard, spawning from pipe 2, on all difficulties. <syntaxhighlight lang=""> SU_A10 : 2-Green </syntaxhighlight> A single red lizard, spawning from pipe 3, on Hunter only. <syntaxhighlight lang=""> (2)SU_A10 : 3-Red </syntaxhighlight> A hoard of 5 yellow lizards spawning from pipe 1, on Monk only. <syntaxhighlight lang=""> (1)SU_A10 : 1-Yellow-5 </syntaxhighlight> A Daddy longlegs spawning from pipe 4, but only on easy and normal difficulties. <syntaxhighlight lang=""> (0,1)SU_A10 : 4-Daddy </syntaxhighlight> A very angry white lizard that spawns from pipe 3, on all difficulties. <syntaxhighlight lang=""> SU_A10 : 3-White-{Mean:0.9} </syntaxhighlight> Some enemies require a unique room known as OFFSCREEN. These enemies use special doors that are automatically added to your level to move between rooms. These include vultures, scavengers, leviathans, and miros birds. This example spawns two off screen vultures. <syntaxhighlight lang=""> OFFSCREEN : 0-Vulture-2 </syntaxhighlight> <!--Enemy flags still apply to offscreen enemies. This will spawn a very aggressive KingVulture that will rarely leave the screen if it spots slugcat, but only on Hunter. <syntaxhighlight lang=""> (2)OFFSCREEN : 0-KingVulture-{Mean:1} </syntaxhighlight> <span id="important-quirks-to-creatures"></span> --><!--King Vultures do not read the info set in their 'flags' ~Bro--> === Important quirks === Enemies may be set to spawn from the same nest pipes. However, do not be surprised if they somehow kill each other offscreen very quickly if you do this. A daddy long legs may have no problems consuming an entire hoard of yellow lizards for example. Enemies will often drag you back to their home nest pipes, but may also choose other pipes they like, even in different rooms. During the end of a cycle, almost every enemy will rush to a nearby nest, if they spawned from it or not. Many creatures that would not intuitively appear to nest in pipes, likely does so, you just never reach them before they spawn in game, or their pipes are well hidden. A direct example of this, is that wandering daddy longlegs spawn from pipes, and return to their pipes before the end of a cycle. This includes the daddies inside Five Pebbles, which makes the area significantly easier once the cycle timer has counted down entirely. It is important to understand various enemy interactions to help you build a cohesive and believable ecosystem for an area. Sandbox mode can help you learn which creature is where on the food chain. As well as looking at the interactions of creatures in other regions. Some creatures have very specific requirements for rooms they inhabit. A very game breaking example, is that big spiders and spitting spiders require the ability to reach every wall in a room in some fashion. By pole, or by invisible ceilings out of the camera. If they cannot, the game will lag very badly due to the spider’s failed pathfinding. Some creatures have a heavier performance impact on the game then others. <!--Sandbox mode can help you learn these, as it will show a notice that “too many of this creature will impact performance” when you begin to place too many.--> <!-- the arena threshold seems somewhat arbitrary in present day--> An example is that more then 4 daddy long legs on screen will often lead to lag. Unfortunate development gets around this problem by using the “stuckDaddy” object, as these daddies do not run wandering path finding checks. All creature types can be configured using the dev tool’s map editor to prefer, avoid, stay or be forbidden inside certain rooms while wandering, using Attraction tool. These spawn entries are simply where they will be created from when the player first enters a region. <span id="the-lineage-system"></span> === The Lineage System === Enemy nests may also be configured to use the lineage system. After being killed, this allows a creature to roll a dice at the end of a cycle, and in a certain percent, respawn as its next entry in the lineage. Due to the format however, you cannot decide how many enemies can spawn from the pipe. So a green lizard cannot turn into a hoard of 3 yellow lizards. Only a single yellow lizard. Enemy flags, and difficulty filters still work however. The format is as follows: <syntaxhighlight lang=""> LINEAGE : ROOM : PIPE : STARTENEMY-PERCENT, NEXTENEMY-PERCENT, FINALENEMY-0 </syntaxhighlight> PERCENT is a value between 0 and 1, and is the percent chance that the enemy will move onto its next form. You may have as many forms as you need. However, it is important to ALWAYS mark the last enemy in the lineage with a 0 percent chance to move on. Rain World will crash the moment it attempts to move to the next enemy in a lineage from the last. ==== Examples ==== A green lizard that spawns from pipe 2, that turns into a blue, and then into a red. With a 5% chance each time. <syntaxhighlight lang=""> LINEAGE : SU_B08 : 2 : Green-0.05, Blue-0.05, Red-0 </syntaxhighlight> A poleplant, with a specific height of 10 blocks, and spawning from pipe 3. That has a 10% chance to turn into a monster kelp <syntaxhighlight lang=""> LINEAGE : SU_A02 : 3 : Mimic-{10}-0.1, TentaclePlant-0 </syntaxhighlight> A empty pipe 3, that has a 1% chance to turn into a monster kelp. <syntaxhighlight lang=""> LINEAGE : SU_B02 : 3 : NONE-0.01, TentaclePlant-0 </syntaxhighlight> Lineage applies to offscreen creatures, as well as difficulties! This example from chimney canopy has a 20% chance to turn a vulture into a king vulture after being killed, but only on normal difficulty. <syntaxhighlight lang=""> (0)LINEAGE : OFFSCREEN : 0 : Vulture-0.2, KingVulture-0 </syntaxhighlight> == Bat Migration Blockages == Bat migration blockages section is bounded by <code>BAT MIGRATION BLOCKAGES</code> and <code>END BAT MIGRATION BLOCKAGES</code> tags. These are used specifically to prevent bat flies from entering a room, or pathing through the region to rooms on the other side of it. These are rarely used. However the room directly after the tutorial area in outskirts is set to be one. The format is simply to list each room line by line between the two tags. There are no unique flags. For the example in Outskirts, bat flies cannot enter room SU_A22 because it is between the tags: <syntaxhighlight lang="">BAT MIGRATION BLOCKAGES SU_A22 END BAT MIGRATION BLOCKAGES </syntaxhighlight> [[Category:Content Mods]] a23dcb470e5c2903210d17d5db2eb5bee9b0a963 World File Format 0 114 465 464 2023-04-13T14:47:26Z Bro748 31 Adjusting and expanding creatures table wikitext text/x-wiki {{Cleanup}} [[File:regionFormat.png|thumb|right|alt=regionFormat|regionFormat]] This page describes worldfile format for RW regions. The world_XX.txt file is present in every region Rain World loads, and determines various room settings such as their pipe connections, the spawns of enemies, and specific flags like shelters and gates. NOTE: Creature spawns for the region are generated when you first enter it on a save. Changing room connections or creature spawns in WORLD_XX after that corrupts save data. '''Reset your saveslot or revert your save to before you entered to avoid bugs'''. == Comments == Worldfile format supports comments: if a line starts with double slash (<code>//</code>), it is ignored entirely. == Room Connections == Room connections section is bounded by <code>ROOMS</code> and <code>END ROOMS</code> tags. These control which pipe entrance leads to what room, and vice versa. Unique room flags that specify certain attributes about the room (such as if it is a shelter or a gate room) are set here as well. The format is as follows: <syntaxhighlight lang="">ROOM : door0, door1, door2, etc : FLAG </syntaxhighlight> === Examples === A standard room with two room-connecting pipes. These will form the bulk of your region. <syntaxhighlight lang="">TR_T07 : TR_T01, TR_P02 </syntaxhighlight> A standard room, with five doors. However, pipes 1, 2 and 3 have no connection. Each pipe inside a room has a specific number starting from 0. These can be viewed using the [[Dev Tools]]' map tab, or by entering the room with dev tools enabled and pressing M. <syntaxhighlight lang="">TR_W19 : TR_L05, DISCONNECTED, DISCONNECTED, DISCONNECTED, TR_W18 </syntaxhighlight> A shelter. These rooms will often be copied from other regions when you are first learning how to make a region. All vanilla save rooms have a single door. <syntaxhighlight lang="">TR_S01 : TR_P01 : SHELTER </syntaxhighlight> A region gate. Doors on the other side of the gate are set to DISCONNECTED. They will automatically be shown as connected doors at runtime. If you need to show a save room door specifically on the other side of the gate, you can use the ExitSymbolShelter object, in the dev tool’s object tab to change the door symbols as required. <syntaxhighlight lang="">GATE_SS_TR : DISCONNECTED, TR_L07 : GATE </syntaxhighlight> A swarm room allows batflies to spawn in the room, as long as the map contains bat nests. If the room has bat nests but is not marked as a swarm room, those nests will always be inactive. The dev tools map tab provides the options needed to control where they will migrate and rooms they will avoid. <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> A scavenger outpost. Use in conjunction with ScavengerOutpost placedObject to create a scavenger toll. <syntaxhighlight lang="">SU_C02 : SU_A45, SU_A07 : SCAVOUTPOST </syntaxhighlight> === Understanding door connections === [[File:regionFormatConnection.png|thumb|none|alt=regionFormatConnection|regionFormatConnection]] For a door to be properly connected, both ends must point to each other using valid doors. For this example, both rooms will have two doors. Door0 will be on the left, and door1 on the right. Door indices are decided specifically for your room, so be sure to check in game how your doors have been assigned by the [[Level Editor]]. The DT Map tab can also be used to see the links between doors. As in the picture to the right. Properly connected doors will show both lines pointing to the set door on the other end. Doors with incorrect links will point off to the bottom right <!--(A disconnected door will also do this,)--> <!--do fucking what--> and a door connected to another room, but that room has no door back (or lacks enough doors!) will point to the center of the room on the map tab page. <syntaxhighlight lang=""> RG_ROOM1 : DISCONNECTED, RG_ROOM2 </syntaxhighlight> <syntaxhighlight lang=""> RG_ROOM2: RG_ROOM1 </syntaxhighlight> Room1 will have its right hand door connected to Room2. Because of this, we need to use DISCONNECTED as a placeholder for its left hand door, door0. Then set door1 to connect to Room2 Room2 will connect to Room1 using door0. Due to this, we do not need to define the right hand door. It will assume it to be disconnected. === Room Tags === Room tags assign certain properties to rooms depending on what the tag is. Tags are assigned like <syntaxhighlight lang=""> [ROOM] : [CONNECTIONS] : [TAG] </syntaxhighlight> Example: <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> {|class="wikitable" !width="18%"| '''<u>Tag</u>''' !width="81%"| '''<u>Function</u>''' |- | SHELTER | Makes the room a shelter. When there are multiple pipes in the room: the animated door is placed at the bottom right most pipe. |- | ANCIENTSHELTER | Makes the room an Outer Expanse style shelter. |- | GATE | Makes the room a gate. Entrances on the other side of the gate are set to DISCONNECTED, and are shown automatically to be connected. |- | SWARMROOM | Allows batflies to be spawned from batfly hives. |- | PERF_HEAVY | Causes the room to be abstractized quicker when player is not inside, can reduce offscreen performance toll of very large rooms. |- | SCAVOUTPOST | Makes the room into a scavenger outpost. Scavs will spawn here and only let you pass if you have a pearl. The exact outpost location is set by the “ScavengerOutpost” devtools object. |- | SCAVTRADER | Spawns a scavenger merchant into the room. Will trade items with you. The merchant is controlled by the “TradeOutpost” devtools object. |- | NOTRACKERS | Disallows key items from saving in the room (for when the 'Key item tracking' Remix setting is turned on) |- | ARENA | Causes creature spawns in the room to stay in their den until activated by an HRGuard (requires MSC!) |} === Important quirks to rooms and doors === When setting up your region, be sure that you always use your region’s prefix to help each room have a unique name. If not, Rain World will treat repeated names as being other rooms, and even re-use rooms from other region folders entirely. If you don’t use your region prefix, changes made with devtools can also wind up getting saved to unexpected places. To avoid these problems, always prefix your room with its region code, and give them unique names. Multiple pipes in a room may all go to the same room. However, these will all act like a single pipe, and you will not be able to set the specific destination pipes. There are no cases in vanilla Rain World where multiple pipes in the current room lead to the same next room. They will all lead to separate rooms. For example, if you had four pipes leading from one room to another. you would need to create a minimum of three unique rooms for each of the other pipes to act as an interconnection. == Creature Spawns == Creature spawn data section is bounded by <code>CREATURES</code> and <code>END CREATURES</code> tags. Rain World only creates creature spawns when you enter a region for the first time on a save<!--, or after an excessive number of cycles has passed--><!--never heard of it before, may be bogus ~thalber-->. {|class="wikitable" !align="center" width="12%"| '''Lizards''' !align="center" width="25%"| '''Insects''' !align="center" width="13%"| '''Amphibians''' !align="center" width="18%"| '''Flying''' !align="center" width="13%"| '''Plants''' !align="center" width="15%"| '''Other''' |- |align="center"| Pink, PinkLizard |align="center"| Spider |align="center"| Salamander |align="center"| CicadaA |align="center"| PoleMimic, Mimic |align="center"| Scavenger |- |align="center"| Green, GreenLizard |align="center"| Small Centipede, SmallCentipede |align="center"| Leech |align="center"| CicadaB |align="center"| Tentacle, TentaclePlant, Tentacle Plant |align="center"| Lantern Mouse, LanternMouse, Mouse |- |align="center"| Blue, BlueLizard |align="center"| Centipede, Centi, Cent |align="center"| SeaLeech, Sea Leech |align="center"| Vulture |align="center"| |align="center"| Worm, Garbage Worm |- |align="center"| Yellow, YellowLizard |align="center"| Red Centipede, RedCenti, RedCentipede |align="center"| JetFish, Jet Fish |align="center"| KingVulture, King Vulture |align="center"| |align="center"| Miros, MirosBird |- |align="center"| White, WhiteLizard |align="center"| DropBug, DropWig |align="center"| Snail |align="center"| Needle, Needle Worm, BigNeedle, BigNeedleWorm |align="center"| |align="center"| Tube, TubeWorm, Tube Worm |- |align="center"| Black, BlackLizard |align="center"| BigSpider |align="center"| Lev, Leviathan, BigEel, Big Eel |align="center"| SmallNeedleWorm, SmallNeedle |align="center"| |align="center"| Bro, BroLongLegs, BrotherLongLegs |- |align="center"| Cyan, CyanLizard |align="center"| SpitterSpider |align="center"| |align="center"| Centiwing |align="center"| |align="center"| Daddy, DaddyLongLegs |- |align="center"| Red, RedLizard |align="center"| EggBug |align="center"| |align="center"| Cicada* |align="center"| |align="center"| Deer |} {|class="wikitable" !colspan="5"|More Slugcats Creatures |- !align="center" width="12%"| '''Lizards''' !align="center" width="25%"| '''Insects''' !align="center" width="13%"| '''Amphibians''' !align="center" width="18%"| '''Flying''' !align="center" width="28%"| '''Other''' |- |align="center"| Caramel, ZoopLizard |align="center"| AquaCenti, AquaCentipede, Aquacenti, Aquapede |align="center"| JungleLeech |align="center"| MirosVulture, Miros Vulture |align="center"| Elite, ScavengerElite, EliteScavenger, Scavenger Elite, Elite Scavenger |- |align="center"| Eel, EelLizard |align="center"| MotherSpider, Mother Spider |align="center"| |align="center"| |align="center"| TerrorLongLegs, Terror |- |align="center"| Strawberry, ZoopLizard |align="center"| FireBug, HellBug |align="center"| |align="center"| |align="center"| HunterDaddy |- |align="center"| Train, TrainLizard |align="center"| Yeek |align="center"| |align="center"| |align="center"| Inspector |} (Multiple names in a single box are interchangeable) (*) Switches between CicadaA and CicadaB) <syntaxhighlight lang=""> //Creature spawns can be specific to a certain character. (0, 1) makes something appear for monk and survivor, (2) only for hunter (character filter)ROOM : PipeNumber-Creature-{optional flags}-Count </syntaxhighlight> === Creature Flags === <!--'Flags' is a bad name for this, I think 'tags' would be more appropriate ~bro--> Creature flags set certain properties of the creature. Any flag can be written to any creature, but it will be ignored if they are not one of the following matches: Lizards may have the {mean:x.x} flag, with x.x representing a number ranging from 0.0 to 1.0 (eg, {Mean:0.6}) This makes the lizard act more aggressively Centipedes may have the {x.x} flag, being a number ranging from 0.0 to 1.0 (eg, {0.7}) This sets the centipede size, with 0.0 being a Small Centipede and 1.0 being an Overgrown Centipede Pole plants may have the {xx} flag, being any non-negative integer (eg, {15}) This sets the length of the pole plant in tiles === Examples === A single green lizard, spawning from pipe 2, on all difficulties. <syntaxhighlight lang=""> SU_A10 : 2-Green </syntaxhighlight> A single red lizard, spawning from pipe 3, on Hunter only. <syntaxhighlight lang=""> (2)SU_A10 : 3-Red </syntaxhighlight> A hoard of 5 yellow lizards spawning from pipe 1, on Monk only. <syntaxhighlight lang=""> (1)SU_A10 : 1-Yellow-5 </syntaxhighlight> A Daddy longlegs spawning from pipe 4, but only on easy and normal difficulties. <syntaxhighlight lang=""> (0,1)SU_A10 : 4-Daddy </syntaxhighlight> A very angry white lizard that spawns from pipe 3, on all difficulties. <syntaxhighlight lang=""> SU_A10 : 3-White-{Mean:0.9} </syntaxhighlight> Some enemies require a unique room known as OFFSCREEN. These enemies use special doors that are automatically added to your level to move between rooms. These include vultures, scavengers, leviathans, and miros birds. This example spawns two off screen vultures. <syntaxhighlight lang=""> OFFSCREEN : 0-Vulture-2 </syntaxhighlight> <!--Enemy flags still apply to offscreen enemies. This will spawn a very aggressive KingVulture that will rarely leave the screen if it spots slugcat, but only on Hunter. <syntaxhighlight lang=""> (2)OFFSCREEN : 0-KingVulture-{Mean:1} </syntaxhighlight> <span id="important-quirks-to-creatures"></span> --><!--King Vultures do not read the info set in their 'flags' ~Bro--> === Important quirks === Enemies may be set to spawn from the same nest pipes. However, do not be surprised if they somehow kill each other offscreen very quickly if you do this. A daddy long legs may have no problems consuming an entire hoard of yellow lizards for example. Enemies will often drag you back to their home nest pipes, but may also choose other pipes they like, even in different rooms. During the end of a cycle, almost every enemy will rush to a nearby nest, if they spawned from it or not. Many creatures that would not intuitively appear to nest in pipes, likely does so, you just never reach them before they spawn in game, or their pipes are well hidden. A direct example of this, is that wandering daddy longlegs spawn from pipes, and return to their pipes before the end of a cycle. This includes the daddies inside Five Pebbles, which makes the area significantly easier once the cycle timer has counted down entirely. It is important to understand various enemy interactions to help you build a cohesive and believable ecosystem for an area. Sandbox mode can help you learn which creature is where on the food chain. As well as looking at the interactions of creatures in other regions. Some creatures have very specific requirements for rooms they inhabit. A very game breaking example, is that big spiders and spitting spiders require the ability to reach every wall in a room in some fashion. By pole, or by invisible ceilings out of the camera. If they cannot, the game will lag very badly due to the spider’s failed pathfinding. Some creatures have a heavier performance impact on the game then others. <!--Sandbox mode can help you learn these, as it will show a notice that “too many of this creature will impact performance” when you begin to place too many.--> <!-- the arena threshold seems somewhat arbitrary in present day--> An example is that more then 4 daddy long legs on screen will often lead to lag. Unfortunate development gets around this problem by using the “stuckDaddy” object, as these daddies do not run wandering path finding checks. All creature types can be configured using the dev tool’s map editor to prefer, avoid, stay or be forbidden inside certain rooms while wandering, using Attraction tool. These spawn entries are simply where they will be created from when the player first enters a region. <span id="the-lineage-system"></span> === The Lineage System === Enemy nests may also be configured to use the lineage system. After being killed, this allows a creature to roll a dice at the end of a cycle, and in a certain percent, respawn as its next entry in the lineage. Due to the format however, you cannot decide how many enemies can spawn from the pipe. So a green lizard cannot turn into a hoard of 3 yellow lizards. Only a single yellow lizard. Enemy flags, and difficulty filters still work however. The format is as follows: <syntaxhighlight lang=""> LINEAGE : ROOM : PIPE : STARTENEMY-PERCENT, NEXTENEMY-PERCENT, FINALENEMY-0 </syntaxhighlight> PERCENT is a value between 0 and 1, and is the percent chance that the enemy will move onto its next form. You may have as many forms as you need. However, it is important to ALWAYS mark the last enemy in the lineage with a 0 percent chance to move on. Rain World will crash the moment it attempts to move to the next enemy in a lineage from the last. ==== Examples ==== A green lizard that spawns from pipe 2, that turns into a blue, and then into a red. With a 5% chance each time. <syntaxhighlight lang=""> LINEAGE : SU_B08 : 2 : Green-0.05, Blue-0.05, Red-0 </syntaxhighlight> A poleplant, with a specific height of 10 blocks, and spawning from pipe 3. That has a 10% chance to turn into a monster kelp <syntaxhighlight lang=""> LINEAGE : SU_A02 : 3 : Mimic-{10}-0.1, TentaclePlant-0 </syntaxhighlight> A empty pipe 3, that has a 1% chance to turn into a monster kelp. <syntaxhighlight lang=""> LINEAGE : SU_B02 : 3 : NONE-0.01, TentaclePlant-0 </syntaxhighlight> Lineage applies to offscreen creatures, as well as difficulties! This example from chimney canopy has a 20% chance to turn a vulture into a king vulture after being killed, but only on normal difficulty. <syntaxhighlight lang=""> (0)LINEAGE : OFFSCREEN : 0 : Vulture-0.2, KingVulture-0 </syntaxhighlight> == Bat Migration Blockages == Bat migration blockages section is bounded by <code>BAT MIGRATION BLOCKAGES</code> and <code>END BAT MIGRATION BLOCKAGES</code> tags. These are used specifically to prevent bat flies from entering a room, or pathing through the region to rooms on the other side of it. These are rarely used. However the room directly after the tutorial area in outskirts is set to be one. The format is simply to list each room line by line between the two tags. There are no unique flags. For the example in Outskirts, bat flies cannot enter room SU_A22 because it is between the tags: <syntaxhighlight lang="">BAT MIGRATION BLOCKAGES SU_A22 END BAT MIGRATION BLOCKAGES </syntaxhighlight> [[Category:Content Mods]] 2b96b38cb4a2114cb66f76be854bb92e20857106 466 465 2023-04-13T17:03:26Z Bro748 31 Creature flags table wikitext text/x-wiki {{Cleanup}} [[File:regionFormat.png|thumb|right|alt=regionFormat|regionFormat]] This page describes worldfile format for RW regions. The world_XX.txt file is present in every region Rain World loads, and determines various room settings such as their pipe connections, the spawns of enemies, and specific flags like shelters and gates. NOTE: Creature spawns for the region are generated when you first enter it on a save. Changing room connections or creature spawns in WORLD_XX after that corrupts save data. '''Reset your saveslot or revert your save to before you entered to avoid bugs'''. == Comments == Worldfile format supports comments: if a line starts with double slash (<code>//</code>), it is ignored entirely. == Room Connections == Room connections section is bounded by <code>ROOMS</code> and <code>END ROOMS</code> tags. These control which pipe entrance leads to what room, and vice versa. Unique room flags that specify certain attributes about the room (such as if it is a shelter or a gate room) are set here as well. The format is as follows: <syntaxhighlight lang="">ROOM : door0, door1, door2, etc : FLAG </syntaxhighlight> === Examples === A standard room with two room-connecting pipes. These will form the bulk of your region. <syntaxhighlight lang="">TR_T07 : TR_T01, TR_P02 </syntaxhighlight> A standard room, with five doors. However, pipes 1, 2 and 3 have no connection. Each pipe inside a room has a specific number starting from 0. These can be viewed using the [[Dev Tools]]' map tab, or by entering the room with dev tools enabled and pressing M. <syntaxhighlight lang="">TR_W19 : TR_L05, DISCONNECTED, DISCONNECTED, DISCONNECTED, TR_W18 </syntaxhighlight> A shelter. These rooms will often be copied from other regions when you are first learning how to make a region. All vanilla save rooms have a single door. <syntaxhighlight lang="">TR_S01 : TR_P01 : SHELTER </syntaxhighlight> A region gate. Doors on the other side of the gate are set to DISCONNECTED. They will automatically be shown as connected doors at runtime. If you need to show a save room door specifically on the other side of the gate, you can use the ExitSymbolShelter object, in the dev tool’s object tab to change the door symbols as required. <syntaxhighlight lang="">GATE_SS_TR : DISCONNECTED, TR_L07 : GATE </syntaxhighlight> A swarm room allows batflies to spawn in the room, as long as the map contains bat nests. If the room has bat nests but is not marked as a swarm room, those nests will always be inactive. The dev tools map tab provides the options needed to control where they will migrate and rooms they will avoid. <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> A scavenger outpost. Use in conjunction with ScavengerOutpost placedObject to create a scavenger toll. <syntaxhighlight lang="">SU_C02 : SU_A45, SU_A07 : SCAVOUTPOST </syntaxhighlight> === Understanding door connections === [[File:regionFormatConnection.png|thumb|none|alt=regionFormatConnection|regionFormatConnection]] For a door to be properly connected, both ends must point to each other using valid doors. For this example, both rooms will have two doors. Door0 will be on the left, and door1 on the right. Door indices are decided specifically for your room, so be sure to check in game how your doors have been assigned by the [[Level Editor]]. The DT Map tab can also be used to see the links between doors. As in the picture to the right. Properly connected doors will show both lines pointing to the set door on the other end. Doors with incorrect links will point off to the bottom right <!--(A disconnected door will also do this,)--> <!--do fucking what--> and a door connected to another room, but that room has no door back (or lacks enough doors!) will point to the center of the room on the map tab page. <syntaxhighlight lang=""> RG_ROOM1 : DISCONNECTED, RG_ROOM2 </syntaxhighlight> <syntaxhighlight lang=""> RG_ROOM2: RG_ROOM1 </syntaxhighlight> Room1 will have its right hand door connected to Room2. Because of this, we need to use DISCONNECTED as a placeholder for its left hand door, door0. Then set door1 to connect to Room2 Room2 will connect to Room1 using door0. Due to this, we do not need to define the right hand door. It will assume it to be disconnected. === Room Tags === Room tags assign certain properties to rooms depending on what the tag is. Tags are assigned like <syntaxhighlight lang=""> [ROOM] : [CONNECTIONS] : [TAG] </syntaxhighlight> Example: <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> {|class="wikitable" !width="18%"| '''<u>Tag</u>''' !width="81%"| '''<u>Function</u>''' |- | SHELTER | Makes the room a shelter. When there are multiple pipes in the room: the animated door is placed at the bottom right most pipe. |- | ANCIENTSHELTER | Makes the room an Outer Expanse style shelter. |- | GATE | Makes the room a gate. Entrances on the other side of the gate are set to DISCONNECTED, and are shown automatically to be connected. |- | SWARMROOM | Allows batflies to be spawned from batfly hives. |- | PERF_HEAVY | Causes the room to be abstractized quicker when player is not inside, can reduce offscreen performance toll of very large rooms. |- | SCAVOUTPOST | Makes the room into a scavenger outpost. Scavs will spawn here and only let you pass if you have a pearl. The exact outpost location is set by the “ScavengerOutpost” devtools object. |- | SCAVTRADER | Spawns a scavenger merchant into the room. Will trade items with you. The merchant is controlled by the “TradeOutpost” devtools object. |- | NOTRACKERS | Disallows key items from saving in the room (for when the 'Key item tracking' Remix setting is turned on) |- | ARENA | Causes creature spawns in the room to stay in their den until activated by an HRGuard (requires MSC!) |} === Important quirks to rooms and doors === When setting up your region, be sure that you always use your region’s prefix to help each room have a unique name. If not, Rain World will treat repeated names as being other rooms, and even re-use rooms from other region folders entirely. If you don’t use your region prefix, changes made with devtools can also wind up getting saved to unexpected places. To avoid these problems, always prefix your room with its region code, and give them unique names. Multiple pipes in a room may all go to the same room. However, these will all act like a single pipe, and you will not be able to set the specific destination pipes. There are no cases in vanilla Rain World where multiple pipes in the current room lead to the same next room. They will all lead to separate rooms. For example, if you had four pipes leading from one room to another. you would need to create a minimum of three unique rooms for each of the other pipes to act as an interconnection. == Creature Spawns == Creature spawn data section is bounded by <code>CREATURES</code> and <code>END CREATURES</code> tags. Rain World only creates creature spawns when you enter a region for the first time on a save<!--, or after an excessive number of cycles has passed--><!--never heard of it before, may be bogus ~thalber-->. {|class="wikitable" !align="center" width="12%"| '''Lizards''' !align="center" width="25%"| '''Insects''' !align="center" width="13%"| '''Amphibians''' !align="center" width="18%"| '''Flying''' !align="center" width="13%"| '''Plants''' !align="center" width="15%"| '''Other''' |- |align="center"| Pink, PinkLizard |align="center"| Spider |align="center"| Salamander |align="center"| CicadaA |align="center"| PoleMimic, Mimic |align="center"| Scavenger |- |align="center"| Green, GreenLizard |align="center"| Small Centipede, SmallCentipede |align="center"| Leech |align="center"| CicadaB |align="center"| Tentacle, TentaclePlant, Tentacle Plant |align="center"| Lantern Mouse, LanternMouse, Mouse |- |align="center"| Blue, BlueLizard |align="center"| Centipede, Centi, Cent |align="center"| SeaLeech, Sea Leech |align="center"| Vulture |align="center"| |align="center"| Worm, Garbage Worm |- |align="center"| Yellow, YellowLizard |align="center"| Red Centipede, RedCenti, RedCentipede |align="center"| JetFish, Jet Fish |align="center"| KingVulture, King Vulture |align="center"| |align="center"| Miros, MirosBird |- |align="center"| White, WhiteLizard |align="center"| DropBug, DropWig |align="center"| Snail |align="center"| Needle, Needle Worm, BigNeedle, BigNeedleWorm |align="center"| |align="center"| Tube, TubeWorm, Tube Worm |- |align="center"| Black, BlackLizard |align="center"| BigSpider |align="center"| Lev, Leviathan, BigEel, Big Eel |align="center"| SmallNeedleWorm, SmallNeedle |align="center"| |align="center"| Bro, BroLongLegs, BrotherLongLegs |- |align="center"| Cyan, CyanLizard |align="center"| SpitterSpider |align="center"| |align="center"| Centiwing |align="center"| |align="center"| Daddy, DaddyLongLegs |- |align="center"| Red, RedLizard |align="center"| EggBug |align="center"| |align="center"| Cicada* |align="center"| |align="center"| Deer |} {|class="wikitable" !colspan="5"|More Slugcats Creatures |- !align="center" width="12%"| '''Lizards''' !align="center" width="25%"| '''Insects''' !align="center" width="13%"| '''Amphibians''' !align="center" width="18%"| '''Flying''' !align="center" width="28%"| '''Other''' |- |align="center"| Caramel, ZoopLizard |align="center"| AquaCenti, AquaCentipede, Aquacenti, Aquapede |align="center"| JungleLeech |align="center"| MirosVulture, Miros Vulture |align="center"| Elite, ScavengerElite, EliteScavenger, Scavenger Elite, Elite Scavenger |- |align="center"| Eel, EelLizard |align="center"| MotherSpider, Mother Spider |align="center"| |align="center"| |align="center"| TerrorLongLegs, Terror |- |align="center"| Strawberry, ZoopLizard |align="center"| FireBug, HellBug |align="center"| |align="center"| |align="center"| HunterDaddy |- |align="center"| Train, TrainLizard |align="center"| Yeek |align="center"| |align="center"| |align="center"| Inspector |} (Multiple names in a single box are interchangeable) (*) Switches between CicadaA and CicadaB) <syntaxhighlight lang=""> //Creature spawns can be specific to a certain character. (0, 1) makes something appear for monk and survivor, (2) only for hunter (character filter)ROOM : PipeNumber-Creature-{optional flags}-Count </syntaxhighlight> === Creature Flags === <!--'Flags' is a bad name for this, I think 'tags' would be more appropriate ~bro--> Creature flags set certain properties of the creature. Any flag can be written to any creature, but it will be ignored if they are not one of the following matches: {|class="wikitable" |- !width="8%"| '''Flag''' !width="44%"| '''Description''' !width="23%"| '''Example''' |- | PreCycle || Creature wakes during precycles then go back to bed at normal start of cycle || LM_D02 : 5-Jet Fish-{PreCycle} |- | IgnoreCycle || Creature wakes at normal start of cycle and doesn't return to their den at cycle end\night || UW_J01 : 3-Yellow-{Ignorecycle} |- | Night || Creature wakes at start of night || UW_A02 : 2-SpitterSpider-{Night} |- | TentacleImmune || Creature doesn't get grabbed by DLLs, protos, or wormgrass (unused in-game) || RM_F02 : 6-Inspector-{TentacleImmune} |- | Lavasafe || Creature can swim unharmed in lethal water (unused in-game) || HR_R14 : 2-Salamander-{Lavasafe}-3 |- | Voidsea || Turns the creature gold and makes them Lavasafe. Only works on the following creatures: RedLizard, RedCentipede, BigSpider, DaddyLongLegs, BrotherLongLegs, TerrorLongLegs, BigEel, CyanLizard || HR_A04 : 2-RedCentipede-{Voidsea} |- | Winter || Changes the creature's visuals to be more wintery. Only works on the following creatures: BigSpider, SpitterSpider, Yeek, any lizard || (Saint)VS_C04 : 4-Big Spider-3-{Winter} |- | AlternateForm || changes creature's form, does something completely different for each creature. SmallCentipede: turns them green DLL\BLL: turns them to a TLL Vulture\King: makes them albino || LC_longori : 4-Small Centipede-3-{AlternateForm} |- | Mean:<number> || Makes the lizard act more aggressively, with the number determining how aggressive. Only works on Lizards. <number> should be a non-negative value between 0.0 and 1.0 || UW_A09 : 4-White-{Mean:0.7} |- | <number> || Only usable for Pole Plants and Centipedes. Pole Plant: Determines the length in tiles. <number> should be a non-negative integer Centipede: Determines the size. <number> should be a non-negative value between 0.1 and 1.0 || HI_B15 : 3-Centipede-{0.5} HI_A04 : 2-Mimic-{18} |- | Seed:<number> || Creature will always use the specified seed || GW_C02_PAST : 6-Scavenger-{Seed:2837} |- |} === Examples === A single green lizard, spawning from pipe 2, on all difficulties. <syntaxhighlight lang=""> SU_A10 : 2-Green </syntaxhighlight> A single red lizard, spawning from pipe 3, on Hunter only. <syntaxhighlight lang=""> (2)SU_A10 : 3-Red </syntaxhighlight> A hoard of 5 yellow lizards spawning from pipe 1, on Monk only. <syntaxhighlight lang=""> (1)SU_A10 : 1-Yellow-5 </syntaxhighlight> A Daddy longlegs spawning from pipe 4, but only on easy and normal difficulties. <syntaxhighlight lang=""> (0,1)SU_A10 : 4-Daddy </syntaxhighlight> A very angry white lizard that spawns from pipe 3, on all difficulties. <syntaxhighlight lang=""> SU_A10 : 3-White-{Mean:0.9} </syntaxhighlight> Some enemies require a unique room known as OFFSCREEN. These enemies use special doors that are automatically added to your level to move between rooms. These include vultures, scavengers, leviathans, and miros birds. This example spawns two off screen vultures. <syntaxhighlight lang=""> OFFSCREEN : 0-Vulture-2 </syntaxhighlight> <!--Enemy flags still apply to offscreen enemies. This will spawn a very aggressive KingVulture that will rarely leave the screen if it spots slugcat, but only on Hunter. <syntaxhighlight lang=""> (2)OFFSCREEN : 0-KingVulture-{Mean:1} </syntaxhighlight> <span id="important-quirks-to-creatures"></span> --><!--King Vultures do not read the info set in their 'flags' ~Bro--> === Important quirks === Enemies may be set to spawn from the same nest pipes. However, do not be surprised if they somehow kill each other offscreen very quickly if you do this. A daddy long legs may have no problems consuming an entire hoard of yellow lizards for example. Enemies will often drag you back to their home nest pipes, but may also choose other pipes they like, even in different rooms. During the end of a cycle, almost every enemy will rush to a nearby nest, if they spawned from it or not. Many creatures that would not intuitively appear to nest in pipes, likely does so, you just never reach them before they spawn in game, or their pipes are well hidden. A direct example of this, is that wandering daddy longlegs spawn from pipes, and return to their pipes before the end of a cycle. This includes the daddies inside Five Pebbles, which makes the area significantly easier once the cycle timer has counted down entirely. It is important to understand various enemy interactions to help you build a cohesive and believable ecosystem for an area. Sandbox mode can help you learn which creature is where on the food chain. As well as looking at the interactions of creatures in other regions. Some creatures have very specific requirements for rooms they inhabit. A very game breaking example, is that big spiders and spitting spiders require the ability to reach every wall in a room in some fashion. By pole, or by invisible ceilings out of the camera. If they cannot, the game will lag very badly due to the spider’s failed pathfinding. Some creatures have a heavier performance impact on the game then others. <!--Sandbox mode can help you learn these, as it will show a notice that “too many of this creature will impact performance” when you begin to place too many.--> <!-- the arena threshold seems somewhat arbitrary in present day--> An example is that more then 4 daddy long legs on screen will often lead to lag. Unfortunate development gets around this problem by using the “stuckDaddy” object, as these daddies do not run wandering path finding checks. All creature types can be configured using the dev tool’s map editor to prefer, avoid, stay or be forbidden inside certain rooms while wandering, using Attraction tool. These spawn entries are simply where they will be created from when the player first enters a region. <span id="the-lineage-system"></span> === The Lineage System === Enemy nests may also be configured to use the lineage system. After being killed, this allows a creature to roll a dice at the end of a cycle, and in a certain percent, respawn as its next entry in the lineage. Due to the format however, you cannot decide how many enemies can spawn from the pipe. So a green lizard cannot turn into a hoard of 3 yellow lizards. Only a single yellow lizard. Enemy flags, and difficulty filters still work however. The format is as follows: <syntaxhighlight lang=""> LINEAGE : ROOM : PIPE : STARTENEMY-PERCENT, NEXTENEMY-PERCENT, FINALENEMY-0 </syntaxhighlight> PERCENT is a value between 0 and 1, and is the percent chance that the enemy will move onto its next form. You may have as many forms as you need. However, it is important to ALWAYS mark the last enemy in the lineage with a 0 percent chance to move on. Rain World will crash the moment it attempts to move to the next enemy in a lineage from the last. ==== Examples ==== A green lizard that spawns from pipe 2, that turns into a blue, and then into a red. With a 5% chance each time. <syntaxhighlight lang=""> LINEAGE : SU_B08 : 2 : Green-0.05, Blue-0.05, Red-0 </syntaxhighlight> A poleplant, with a specific height of 10 blocks, and spawning from pipe 3. That has a 10% chance to turn into a monster kelp <syntaxhighlight lang=""> LINEAGE : SU_A02 : 3 : Mimic-{10}-0.1, TentaclePlant-0 </syntaxhighlight> A empty pipe 3, that has a 1% chance to turn into a monster kelp. <syntaxhighlight lang=""> LINEAGE : SU_B02 : 3 : NONE-0.01, TentaclePlant-0 </syntaxhighlight> Lineage applies to offscreen creatures, as well as difficulties! This example from chimney canopy has a 20% chance to turn a vulture into a king vulture after being killed, but only on normal difficulty. <syntaxhighlight lang=""> (0)LINEAGE : OFFSCREEN : 0 : Vulture-0.2, KingVulture-0 </syntaxhighlight> == Bat Migration Blockages == Bat migration blockages section is bounded by <code>BAT MIGRATION BLOCKAGES</code> and <code>END BAT MIGRATION BLOCKAGES</code> tags. These are used specifically to prevent bat flies from entering a room, or pathing through the region to rooms on the other side of it. These are rarely used. However the room directly after the tutorial area in outskirts is set to be one. The format is simply to list each room line by line between the two tags. There are no unique flags. For the example in Outskirts, bat flies cannot enter room SU_A22 because it is between the tags: <syntaxhighlight lang="">BAT MIGRATION BLOCKAGES SU_A22 END BAT MIGRATION BLOCKAGES </syntaxhighlight> [[Category:Content Mods]] de54bbdba6a3449de427646b99a37ed43f4b6ccb 467 466 2023-04-13T19:46:55Z Isbjorn52 149 Fixed typo wikitext text/x-wiki {{Cleanup}} [[File:regionFormat.png|thumb|right|alt=regionFormat|regionFormat]] This page describes worldfile format for RW regions. The world_XX.txt file is present in every region Rain World loads, and determines various room settings such as their pipe connections, the spawns of enemies, and specific flags like shelters and gates. NOTE: Creature spawns for the region are generated when you first enter it on a save. Changing room connections or creature spawns in WORLD_XX after that corrupts save data. '''Reset your saveslot or revert your save to before you entered to avoid bugs'''. == Comments == Worldfile format supports comments: if a line starts with double slash (<code>//</code>), it is ignored entirely. == Room Connections == Room connections section is bounded by <code>ROOMS</code> and <code>END ROOMS</code> tags. These control which pipe entrance leads to what room, and vice versa. Unique room flags that specify certain attributes about the room (such as if it is a shelter or a gate room) are set here as well. The format is as follows: <syntaxhighlight lang="">ROOM : door0, door1, door2, etc : FLAG </syntaxhighlight> === Examples === A standard room with two room-connecting pipes. These will form the bulk of your region. <syntaxhighlight lang="">TR_T07 : TR_T01, TR_P02 </syntaxhighlight> A standard room, with five doors. However, pipes 1, 2 and 3 have no connection. Each pipe inside a room has a specific number starting from 0. These can be viewed using the [[Dev Tools]]' map tab, or by entering the room with dev tools enabled and pressing M. <syntaxhighlight lang="">TR_W19 : TR_L05, DISCONNECTED, DISCONNECTED, DISCONNECTED, TR_W18 </syntaxhighlight> A shelter. These rooms will often be copied from other regions when you are first learning how to make a region. All vanilla save rooms have a single door. <syntaxhighlight lang="">TR_S01 : TR_P01 : SHELTER </syntaxhighlight> A region gate. Doors on the other side of the gate are set to DISCONNECTED. They will automatically be shown as connected doors at runtime. If you need to show a save room door specifically on the other side of the gate, you can use the ExitSymbolShelter object, in the dev tool’s object tab to change the door symbols as required. <syntaxhighlight lang="">GATE_SS_TR : DISCONNECTED, TR_L07 : GATE </syntaxhighlight> A swarm room allows batflies to spawn in the room, as long as the map contains bat nests. If the room has bat nests but is not marked as a swarm room, those nests will always be inactive. The dev tools map tab provides the options needed to control where they will migrate and rooms they will avoid. <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> A scavenger outpost. Use in conjunction with ScavengerOutpost placedObject to create a scavenger toll. <syntaxhighlight lang="">SU_C02 : SU_A45, SU_A07 : SCAVOUTPOST </syntaxhighlight> === Understanding door connections === [[File:regionFormatConnection.png|thumb|none|alt=regionFormatConnection|regionFormatConnection]] For a door to be properly connected, both ends must point to each other using valid doors. For this example, both rooms will have two doors. Door0 will be on the left, and door1 on the right. Door indices are decided specifically for your room, so be sure to check in game how your doors have been assigned by the [[Level Editor]]. The DT Map tab can also be used to see the links between doors. As in the picture to the right. Properly connected doors will show both lines pointing to the set door on the other end. Doors with incorrect links will point off to the bottom right <!--(A disconnected door will also do this,)--> <!--do fucking what--> and a door connected to another room, but that room has no door back (or lacks enough doors!) will point to the center of the room on the map tab page. <syntaxhighlight lang=""> RG_ROOM1 : DISCONNECTED, RG_ROOM2 </syntaxhighlight> <syntaxhighlight lang=""> RG_ROOM2: RG_ROOM1 </syntaxhighlight> Room1 will have its right hand door connected to Room2. Because of this, we need to use DISCONNECTED as a placeholder for its left hand door, door0. Then set door1 to connect to Room2 Room2 will connect to Room1 using door0. Due to this, we do not need to define the right hand door. It will assume it to be disconnected. === Room Tags === Room tags assign certain properties to rooms depending on what the tag is. Tags are assigned like <syntaxhighlight lang=""> [ROOM] : [CONNECTIONS] : [TAG] </syntaxhighlight> Example: <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> {|class="wikitable" !width="18%"| '''<u>Tag</u>''' !width="81%"| '''<u>Function</u>''' |- | SHELTER | Makes the room a shelter. When there are multiple pipes in the room: the animated door is placed at the bottom right most pipe. |- | ANCIENTSHELTER | Makes the room an Outer Expanse style shelter. |- | GATE | Makes the room a gate. Entrances on the other side of the gate are set to DISCONNECTED, and are shown automatically to be connected. |- | SWARMROOM | Allows batflies to be spawned from batfly hives. |- | PERF_HEAVY | Causes the room to be abstractized quicker when player is not inside, can reduce offscreen performance toll of very large rooms. |- | SCAVOUTPOST | Makes the room into a scavenger outpost. Scavs will spawn here and only let you pass if you have a pearl. The exact outpost location is set by the “ScavengerOutpost” devtools object. |- | SCAVTRADER | Spawns a scavenger merchant into the room. Will trade items with you. The merchant is controlled by the “TradeOutpost” devtools object. |- | NOTRACKERS | Disallows key items from saving in the room (for when the 'Key item tracking' Remix setting is turned on) |- | ARENA | Causes creature spawns in the room to stay in their den until activated by an HRGuard (requires MSC!) |} === Important quirks to rooms and doors === When setting up your region, be sure that you always use your region’s prefix to help each room have a unique name. If not, Rain World will treat repeated names as being other rooms, and even re-use rooms from other region folders entirely. If you don’t use your region prefix, changes made with devtools can also wind up getting saved to unexpected places. To avoid these problems, always prefix your room with its region code, and give them unique names. Multiple pipes in a room may all go to the same room. However, these will all act like a single pipe, and you will not be able to set the specific destination pipes. There are no cases in vanilla Rain World where multiple pipes in the current room lead to the same next room. They will all lead to separate rooms. For example, if you had four pipes leading from one room to another. you would need to create a minimum of three unique rooms for each of the other pipes to act as an interconnection. == Creature Spawns == Creature spawn data section is bounded by <code>CREATURES</code> and <code>END CREATURES</code> tags. Rain World only creates creature spawns when you enter a region for the first time on a save<!--, or after an excessive number of cycles has passed--><!--never heard of it before, may be bogus ~thalber-->. {|class="wikitable" !align="center" width="12%"| '''Lizards''' !align="center" width="25%"| '''Insects''' !align="center" width="13%"| '''Amphibians''' !align="center" width="18%"| '''Flying''' !align="center" width="13%"| '''Plants''' !align="center" width="15%"| '''Other''' |- |align="center"| Pink, PinkLizard |align="center"| Spider |align="center"| Salamander |align="center"| CicadaA |align="center"| PoleMimic, Mimic |align="center"| Scavenger |- |align="center"| Green, GreenLizard |align="center"| Small Centipede, SmallCentipede |align="center"| Leech |align="center"| CicadaB |align="center"| Tentacle, TentaclePlant, Tentacle Plant |align="center"| Lantern Mouse, LanternMouse, Mouse |- |align="center"| Blue, BlueLizard |align="center"| Centipede, Centi, Cent |align="center"| SeaLeech, Sea Leech |align="center"| Vulture |align="center"| |align="center"| Worm, Garbage Worm |- |align="center"| Yellow, YellowLizard |align="center"| Red Centipede, RedCenti, RedCentipede |align="center"| JetFish, Jet Fish |align="center"| KingVulture, King Vulture |align="center"| |align="center"| Miros, MirosBird |- |align="center"| White, WhiteLizard |align="center"| DropBug, DropWig |align="center"| Snail |align="center"| Needle, Needle Worm, BigNeedle, BigNeedleWorm |align="center"| |align="center"| Tube, TubeWorm, Tube Worm |- |align="center"| Black, BlackLizard |align="center"| BigSpider |align="center"| Lev, Leviathan, BigEel, Big Eel |align="center"| SmallNeedleWorm, SmallNeedle |align="center"| |align="center"| Bro, BroLongLegs, BrotherLongLegs |- |align="center"| Cyan, CyanLizard |align="center"| SpitterSpider |align="center"| |align="center"| Centiwing |align="center"| |align="center"| Daddy, DaddyLongLegs |- |align="center"| Red, RedLizard |align="center"| EggBug |align="center"| |align="center"| Cicada* |align="center"| |align="center"| Deer |} {|class="wikitable" !colspan="5"|More Slugcats Creatures |- !align="center" width="12%"| '''Lizards''' !align="center" width="25%"| '''Insects''' !align="center" width="13%"| '''Amphibians''' !align="center" width="18%"| '''Flying''' !align="center" width="28%"| '''Other''' |- |align="center"| Caramel, SpitLizard |align="center"| AquaCenti, AquaCentipede, Aquacenti, Aquapede |align="center"| JungleLeech |align="center"| MirosVulture, Miros Vulture |align="center"| Elite, ScavengerElite, EliteScavenger, Scavenger Elite, Elite Scavenger |- |align="center"| Eel, EelLizard |align="center"| MotherSpider, Mother Spider |align="center"| |align="center"| |align="center"| TerrorLongLegs, Terror |- |align="center"| Strawberry, ZoopLizard |align="center"| FireBug, HellBug |align="center"| |align="center"| |align="center"| HunterDaddy |- |align="center"| Train, TrainLizard |align="center"| Yeek |align="center"| |align="center"| |align="center"| Inspector |} (Multiple names in a single box are interchangeable) (*) Switches between CicadaA and CicadaB) <syntaxhighlight lang=""> //Creature spawns can be specific to a certain character. (0, 1) makes something appear for monk and survivor, (2) only for hunter (character filter)ROOM : PipeNumber-Creature-{optional flags}-Count </syntaxhighlight> === Creature Flags === <!--'Flags' is a bad name for this, I think 'tags' would be more appropriate ~bro--> Creature flags set certain properties of the creature. Any flag can be written to any creature, but it will be ignored if they are not one of the following matches: {|class="wikitable" |- !width="8%"| '''Flag''' !width="44%"| '''Description''' !width="23%"| '''Example''' |- | PreCycle || Creature wakes during precycles then go back to bed at normal start of cycle || LM_D02 : 5-Jet Fish-{PreCycle} |- | IgnoreCycle || Creature wakes at normal start of cycle and doesn't return to their den at cycle end\night || UW_J01 : 3-Yellow-{Ignorecycle} |- | Night || Creature wakes at start of night || UW_A02 : 2-SpitterSpider-{Night} |- | TentacleImmune || Creature doesn't get grabbed by DLLs, protos, or wormgrass (unused in-game) || RM_F02 : 6-Inspector-{TentacleImmune} |- | Lavasafe || Creature can swim unharmed in lethal water (unused in-game) || HR_R14 : 2-Salamander-{Lavasafe}-3 |- | Voidsea || Turns the creature gold and makes them Lavasafe. Only works on the following creatures: RedLizard, RedCentipede, BigSpider, DaddyLongLegs, BrotherLongLegs, TerrorLongLegs, BigEel, CyanLizard || HR_A04 : 2-RedCentipede-{Voidsea} |- | Winter || Changes the creature's visuals to be more wintery. Only works on the following creatures: BigSpider, SpitterSpider, Yeek, any lizard || (Saint)VS_C04 : 4-Big Spider-3-{Winter} |- | AlternateForm || changes creature's form, does something completely different for each creature. SmallCentipede: turns them green DLL\BLL: turns them to a TLL Vulture\King: makes them albino || LC_longori : 4-Small Centipede-3-{AlternateForm} |- | Mean:<number> || Makes the lizard act more aggressively, with the number determining how aggressive. Only works on Lizards. <number> should be a non-negative value between 0.0 and 1.0 || UW_A09 : 4-White-{Mean:0.7} |- | <number> || Only usable for Pole Plants and Centipedes. Pole Plant: Determines the length in tiles. <number> should be a non-negative integer Centipede: Determines the size. <number> should be a non-negative value between 0.1 and 1.0 || HI_B15 : 3-Centipede-{0.5} HI_A04 : 2-Mimic-{18} |- | Seed:<number> || Creature will always use the specified seed || GW_C02_PAST : 6-Scavenger-{Seed:2837} |- |} === Examples === A single green lizard, spawning from pipe 2, on all difficulties. <syntaxhighlight lang=""> SU_A10 : 2-Green </syntaxhighlight> A single red lizard, spawning from pipe 3, on Hunter only. <syntaxhighlight lang=""> (2)SU_A10 : 3-Red </syntaxhighlight> A hoard of 5 yellow lizards spawning from pipe 1, on Monk only. <syntaxhighlight lang=""> (1)SU_A10 : 1-Yellow-5 </syntaxhighlight> A Daddy longlegs spawning from pipe 4, but only on easy and normal difficulties. <syntaxhighlight lang=""> (0,1)SU_A10 : 4-Daddy </syntaxhighlight> A very angry white lizard that spawns from pipe 3, on all difficulties. <syntaxhighlight lang=""> SU_A10 : 3-White-{Mean:0.9} </syntaxhighlight> Some enemies require a unique room known as OFFSCREEN. These enemies use special doors that are automatically added to your level to move between rooms. These include vultures, scavengers, leviathans, and miros birds. This example spawns two off screen vultures. <syntaxhighlight lang=""> OFFSCREEN : 0-Vulture-2 </syntaxhighlight> <!--Enemy flags still apply to offscreen enemies. This will spawn a very aggressive KingVulture that will rarely leave the screen if it spots slugcat, but only on Hunter. <syntaxhighlight lang=""> (2)OFFSCREEN : 0-KingVulture-{Mean:1} </syntaxhighlight> <span id="important-quirks-to-creatures"></span> --><!--King Vultures do not read the info set in their 'flags' ~Bro--> === Important quirks === Enemies may be set to spawn from the same nest pipes. However, do not be surprised if they somehow kill each other offscreen very quickly if you do this. A daddy long legs may have no problems consuming an entire hoard of yellow lizards for example. Enemies will often drag you back to their home nest pipes, but may also choose other pipes they like, even in different rooms. During the end of a cycle, almost every enemy will rush to a nearby nest, if they spawned from it or not. Many creatures that would not intuitively appear to nest in pipes, likely does so, you just never reach them before they spawn in game, or their pipes are well hidden. A direct example of this, is that wandering daddy longlegs spawn from pipes, and return to their pipes before the end of a cycle. This includes the daddies inside Five Pebbles, which makes the area significantly easier once the cycle timer has counted down entirely. It is important to understand various enemy interactions to help you build a cohesive and believable ecosystem for an area. Sandbox mode can help you learn which creature is where on the food chain. As well as looking at the interactions of creatures in other regions. Some creatures have very specific requirements for rooms they inhabit. A very game breaking example, is that big spiders and spitting spiders require the ability to reach every wall in a room in some fashion. By pole, or by invisible ceilings out of the camera. If they cannot, the game will lag very badly due to the spider’s failed pathfinding. Some creatures have a heavier performance impact on the game then others. <!--Sandbox mode can help you learn these, as it will show a notice that “too many of this creature will impact performance” when you begin to place too many.--> <!-- the arena threshold seems somewhat arbitrary in present day--> An example is that more then 4 daddy long legs on screen will often lead to lag. Unfortunate development gets around this problem by using the “stuckDaddy” object, as these daddies do not run wandering path finding checks. All creature types can be configured using the dev tool’s map editor to prefer, avoid, stay or be forbidden inside certain rooms while wandering, using Attraction tool. These spawn entries are simply where they will be created from when the player first enters a region. <span id="the-lineage-system"></span> === The Lineage System === Enemy nests may also be configured to use the lineage system. After being killed, this allows a creature to roll a dice at the end of a cycle, and in a certain percent, respawn as its next entry in the lineage. Due to the format however, you cannot decide how many enemies can spawn from the pipe. So a green lizard cannot turn into a hoard of 3 yellow lizards. Only a single yellow lizard. Enemy flags, and difficulty filters still work however. The format is as follows: <syntaxhighlight lang=""> LINEAGE : ROOM : PIPE : STARTENEMY-PERCENT, NEXTENEMY-PERCENT, FINALENEMY-0 </syntaxhighlight> PERCENT is a value between 0 and 1, and is the percent chance that the enemy will move onto its next form. You may have as many forms as you need. However, it is important to ALWAYS mark the last enemy in the lineage with a 0 percent chance to move on. Rain World will crash the moment it attempts to move to the next enemy in a lineage from the last. ==== Examples ==== A green lizard that spawns from pipe 2, that turns into a blue, and then into a red. With a 5% chance each time. <syntaxhighlight lang=""> LINEAGE : SU_B08 : 2 : Green-0.05, Blue-0.05, Red-0 </syntaxhighlight> A poleplant, with a specific height of 10 blocks, and spawning from pipe 3. That has a 10% chance to turn into a monster kelp <syntaxhighlight lang=""> LINEAGE : SU_A02 : 3 : Mimic-{10}-0.1, TentaclePlant-0 </syntaxhighlight> A empty pipe 3, that has a 1% chance to turn into a monster kelp. <syntaxhighlight lang=""> LINEAGE : SU_B02 : 3 : NONE-0.01, TentaclePlant-0 </syntaxhighlight> Lineage applies to offscreen creatures, as well as difficulties! This example from chimney canopy has a 20% chance to turn a vulture into a king vulture after being killed, but only on normal difficulty. <syntaxhighlight lang=""> (0)LINEAGE : OFFSCREEN : 0 : Vulture-0.2, KingVulture-0 </syntaxhighlight> == Bat Migration Blockages == Bat migration blockages section is bounded by <code>BAT MIGRATION BLOCKAGES</code> and <code>END BAT MIGRATION BLOCKAGES</code> tags. These are used specifically to prevent bat flies from entering a room, or pathing through the region to rooms on the other side of it. These are rarely used. However the room directly after the tutorial area in outskirts is set to be one. The format is simply to list each room line by line between the two tags. There are no unique flags. For the example in Outskirts, bat flies cannot enter room SU_A22 because it is between the tags: <syntaxhighlight lang="">BAT MIGRATION BLOCKAGES SU_A22 END BAT MIGRATION BLOCKAGES </syntaxhighlight> [[Category:Content Mods]] b2202c0a828be65ba014908393024cb9c09bf182 468 467 2023-04-14T16:38:12Z Bro748 31 General structure & correct slugcat conditions wikitext text/x-wiki {{Cleanup}} [[File:regionFormat.png|thumb|right|alt=regionFormat|regionFormat]] This page describes worldfile format for RW regions. The world_XX.txt file is present in every region Rain World loads, and determines various room settings such as their pipe connections, the spawns of enemies, and specific flags like shelters and gates. NOTE: Creature spawns for the region are generated when you first enter it on a save. Changing room connections or creature spawns in WORLD_XX after that corrupts save data. '''Reset your saveslot or revert your save to before you entered to avoid bugs'''. == Comments == Worldfile format supports comments: if a line starts with double slash (<code>//</code>), it is ignored entirely. == Format == Worldfile contains 2 to 4 sections, each with a different purpose. The start and end of each section is defined by a line containing only <code>SECTIONNAME</code> and <code>END SECTIONNAME</code> The 4 sections are: <code>CONDITIONAL LINKS</code>, <code>ROOMS</code>, <code>CREATURES</code>, and <code>BAT MIGRATION BLOCKAGES</code>. <code>ROOMS</code> and <code>CREATURES</code> are required, the others are optional. A full world file with no contents will look like this: <syntaxhighlight lang=""> CONDITIONAL LINKS //conditional links go here END CONDITIONAL LINKS ROOMS //rooms go here END ROOMS CREATURES //creatures go here END CREATURES BAT MIGRATION BLOCKAGES //migration blockages go here END BAT MIGRATION BLOCKAGES </syntaxhighlight> == Room Connections == Room connections section is bounded by <code>ROOMS</code> and <code>END ROOMS</code> tags. These control which pipe entrance leads to what room, and vice versa. Unique room flags that specify certain attributes about the room (such as if it is a shelter or a gate room) are set here as well. The format is as follows: <syntaxhighlight lang="">ROOM : door0, door1, door2, etc : FLAG </syntaxhighlight> === Examples === A standard room with two room-connecting pipes. These will form the bulk of your region. <syntaxhighlight lang="">TR_T07 : TR_T01, TR_P02 </syntaxhighlight> A standard room, with five doors. However, pipes 1, 2 and 3 have no connection. Each pipe inside a room has a specific number starting from 0. These can be viewed using the [[Dev Tools]]' map tab, or by entering the room with dev tools enabled and pressing M. <syntaxhighlight lang="">TR_W19 : TR_L05, DISCONNECTED, DISCONNECTED, DISCONNECTED, TR_W18 </syntaxhighlight> A shelter. These rooms will often be copied from other regions when you are first learning how to make a region. All vanilla save rooms have a single door. <syntaxhighlight lang="">TR_S01 : TR_P01 : SHELTER </syntaxhighlight> A region gate. Doors on the other side of the gate are set to DISCONNECTED. They will automatically be shown as connected doors at runtime. If you need to show a save room door specifically on the other side of the gate, you can use the ExitSymbolShelter object, in the dev tool’s object tab to change the door symbols as required. <syntaxhighlight lang="">GATE_SS_TR : DISCONNECTED, TR_L07 : GATE </syntaxhighlight> A swarm room allows batflies to spawn in the room, as long as the map contains bat nests. If the room has bat nests but is not marked as a swarm room, those nests will always be inactive. The dev tools map tab provides the options needed to control where they will migrate and rooms they will avoid. <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> A scavenger outpost. Use in conjunction with ScavengerOutpost placedObject to create a scavenger toll. <syntaxhighlight lang="">SU_C02 : SU_A45, SU_A07 : SCAVOUTPOST </syntaxhighlight> === Understanding door connections === [[File:regionFormatConnection.png|thumb|none|alt=regionFormatConnection|regionFormatConnection]] For a door to be properly connected, both ends must point to each other using valid doors. For this example, both rooms will have two doors. Door0 will be on the left, and door1 on the right. Door indices are decided specifically for your room, so be sure to check in game how your doors have been assigned by the [[Level Editor]]. The DT Map tab can also be used to see the links between doors. As in the picture to the right. Properly connected doors will show both lines pointing to the set door on the other end. Doors with incorrect links will point off to the bottom right <!--(A disconnected door will also do this,)--> <!--do fucking what--> and a door connected to another room, but that room has no door back (or lacks enough doors!) will point to the center of the room on the map tab page. <syntaxhighlight lang=""> RG_ROOM1 : DISCONNECTED, RG_ROOM2 </syntaxhighlight> <syntaxhighlight lang=""> RG_ROOM2: RG_ROOM1 </syntaxhighlight> Room1 will have its right hand door connected to Room2. Because of this, we need to use DISCONNECTED as a placeholder for its left hand door, door0. Then set door1 to connect to Room2 Room2 will connect to Room1 using door0. Due to this, we do not need to define the right hand door. It will assume it to be disconnected. === Room Tags === Room tags assign certain properties to rooms depending on what the tag is. Tags are assigned like <syntaxhighlight lang=""> [ROOM] : [CONNECTIONS] : [TAG] </syntaxhighlight> Example: <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> {|class="wikitable" !width="18%"| '''<u>Tag</u>''' !width="81%"| '''<u>Function</u>''' |- | SHELTER | Makes the room a shelter. When there are multiple pipes in the room: the animated door is placed at the bottom right most pipe. |- | ANCIENTSHELTER | Makes the room an Outer Expanse style shelter. |- | GATE | Makes the room a gate. Entrances on the other side of the gate are set to DISCONNECTED, and are shown automatically to be connected. |- | SWARMROOM | Allows batflies to be spawned from batfly hives. |- | PERF_HEAVY | Causes the room to be abstractized quicker when player is not inside, can reduce offscreen performance toll of very large rooms. |- | SCAVOUTPOST | Makes the room into a scavenger outpost. Scavs will spawn here and only let you pass if you have a pearl. The exact outpost location is set by the “ScavengerOutpost” devtools object. |- | SCAVTRADER | Spawns a scavenger merchant into the room. Will trade items with you. The merchant is controlled by the “TradeOutpost” devtools object. |- | NOTRACKERS | Disallows key items from saving in the room (for when the 'Key item tracking' Remix setting is turned on) |- | ARENA | Causes creature spawns in the room to stay in their den until activated by an HRGuard (requires MSC!) |} === Important quirks to rooms and doors === When setting up your region, be sure that you always use your region’s prefix to help each room have a unique name. If not, Rain World will treat repeated names as being other rooms, and even re-use rooms from other region folders entirely. If you don’t use your region prefix, changes made with devtools can also wind up getting saved to unexpected places. To avoid these problems, always prefix your room with its region code, and give them unique names. Multiple pipes in a room may all go to the same room. However, these will all act like a single pipe, and you will not be able to set the specific destination pipes. There are no cases in vanilla Rain World where multiple pipes in the current room lead to the same next room. They will all lead to separate rooms. For example, if you had four pipes leading from one room to another. you would need to create a minimum of three unique rooms for each of the other pipes to act as an interconnection. == Creature Spawns == Creature spawn data section is bounded by <code>CREATURES</code> and <code>END CREATURES</code> tags. Rain World only creates creature spawns when you enter a region for the first time on a save<!--, or after an excessive number of cycles has passed--><!--never heard of it before, may be bogus ~thalber-->. {|class="wikitable" !align="center" width="12%"| '''Lizards''' !align="center" width="25%"| '''Insects''' !align="center" width="13%"| '''Amphibians''' !align="center" width="18%"| '''Flying''' !align="center" width="13%"| '''Plants''' !align="center" width="15%"| '''Other''' |- |align="center"| Pink, PinkLizard |align="center"| Spider |align="center"| Salamander |align="center"| CicadaA |align="center"| PoleMimic, Mimic |align="center"| Scavenger |- |align="center"| Green, GreenLizard |align="center"| Small Centipede, SmallCentipede |align="center"| Leech |align="center"| CicadaB |align="center"| Tentacle, TentaclePlant, Tentacle Plant |align="center"| Lantern Mouse, LanternMouse, Mouse |- |align="center"| Blue, BlueLizard |align="center"| Centipede, Centi, Cent |align="center"| SeaLeech, Sea Leech |align="center"| Vulture |align="center"| |align="center"| Worm, Garbage Worm |- |align="center"| Yellow, YellowLizard |align="center"| Red Centipede, RedCenti, RedCentipede |align="center"| JetFish, Jet Fish |align="center"| KingVulture, King Vulture |align="center"| |align="center"| Miros, MirosBird |- |align="center"| White, WhiteLizard |align="center"| DropBug, DropWig |align="center"| Snail |align="center"| Needle, Needle Worm, BigNeedle, BigNeedleWorm |align="center"| |align="center"| Tube, TubeWorm, Tube Worm |- |align="center"| Black, BlackLizard |align="center"| BigSpider |align="center"| Lev, Leviathan, BigEel, Big Eel |align="center"| SmallNeedleWorm, SmallNeedle |align="center"| |align="center"| Bro, BroLongLegs, BrotherLongLegs |- |align="center"| Cyan, CyanLizard |align="center"| SpitterSpider |align="center"| |align="center"| Centiwing |align="center"| |align="center"| Daddy, DaddyLongLegs |- |align="center"| Red, RedLizard |align="center"| EggBug |align="center"| |align="center"| Cicada* |align="center"| |align="center"| Deer |} {|class="wikitable" !colspan="5"|More Slugcats Creatures |- !align="center" width="12%"| '''Lizards''' !align="center" width="25%"| '''Insects''' !align="center" width="13%"| '''Amphibians''' !align="center" width="18%"| '''Flying''' !align="center" width="28%"| '''Other''' |- |align="center"| Caramel, SpitLizard |align="center"| AquaCenti, AquaCentipede, Aquacenti, Aquapede |align="center"| JungleLeech |align="center"| MirosVulture, Miros Vulture |align="center"| Elite, ScavengerElite, EliteScavenger, Scavenger Elite, Elite Scavenger |- |align="center"| Eel, EelLizard |align="center"| MotherSpider, Mother Spider |align="center"| |align="center"| |align="center"| TerrorLongLegs, Terror |- |align="center"| Strawberry, ZoopLizard |align="center"| FireBug, HellBug |align="center"| |align="center"| |align="center"| HunterDaddy |- |align="center"| Train, TrainLizard |align="center"| Yeek |align="center"| |align="center"| |align="center"| Inspector |} (Multiple names in a single box are interchangeable) (*) Switches between CicadaA and CicadaB) <syntaxhighlight lang=""> //Creature spawns can be specific to a certain character. (White, Yellow) makes something appear for monk and survivor, (Red) only for hunter (character filter)ROOM : PipeNumber-Creature-{optional flags}-Count Additionally, an "X-" prefix can be added to slugcat-specific spawn filters to invert the filter. For example <code>(<u>X-White,Yellow</u>)CC_A07 : 3-Mimic-{18}</code> would make the spawner appear on any slugcats ''except for'' Survivor and Monk. </syntaxhighlight> === Creature Flags === <!--'Flags' is a bad name for this, I think 'tags' would be more appropriate ~bro--> Creature flags set certain properties of the creature. Any flag can be written to any creature, but it will be ignored if they are not one of the following matches: {|class="wikitable" |- !width="8%"| '''Flag''' !width="44%"| '''Description''' !width="23%"| '''Example''' |- | PreCycle || Creature wakes during precycles then go back to bed at normal start of cycle || LM_D02 : 5-Jet Fish-{PreCycle} |- | IgnoreCycle || Creature wakes at normal start of cycle and doesn't return to their den at cycle end\night || UW_J01 : 3-Yellow-{Ignorecycle} |- | Night || Creature wakes at start of night || UW_A02 : 2-SpitterSpider-{Night} |- | TentacleImmune || Creature doesn't get grabbed by DLLs, protos, or wormgrass (unused in-game) || RM_F02 : 6-Inspector-{TentacleImmune} |- | Lavasafe || Creature can swim unharmed in lethal water (unused in-game) || HR_R14 : 2-Salamander-{Lavasafe}-3 |- | Voidsea || Turns the creature gold and makes them Lavasafe. Only works on the following creatures: RedLizard, RedCentipede, BigSpider, DaddyLongLegs, BrotherLongLegs, TerrorLongLegs, BigEel, CyanLizard || HR_A04 : 2-RedCentipede-{Voidsea} |- | Winter || Changes the creature's visuals to be more wintery. Only works on the following creatures: BigSpider, SpitterSpider, Yeek, any lizard || (Saint)VS_C04 : 4-Big Spider-3-{Winter} |- | AlternateForm || changes creature's form, does something completely different for each creature. SmallCentipede: turns them green DLL\BLL: turns them to a TLL Vulture\King: makes them albino || LC_longori : 4-Small Centipede-3-{AlternateForm} |- | Mean:<number> || Makes the lizard act more aggressively, with the number determining how aggressive. Only works on Lizards. <number> should be a non-negative value between 0.0 and 1.0 || UW_A09 : 4-White-{Mean:0.7} |- | <number> || Only usable for Pole Plants and Centipedes. Pole Plant: Determines the length in tiles. <number> should be a non-negative integer Centipede: Determines the size. <number> should be a non-negative value between 0.1 and 1.0 || HI_B15 : 3-Centipede-{0.5} HI_A04 : 2-Mimic-{18} |- | Seed:<number> || Creature will always use the specified seed || GW_C02_PAST : 6-Scavenger-{Seed:2837} |- |} === Examples === A single green lizard, spawning from pipe 2, on all difficulties. <syntaxhighlight lang=""> SU_A10 : 2-Green </syntaxhighlight> A single red lizard, spawning from pipe 3, on Hunter only. <syntaxhighlight lang=""> (Red)SU_A10 : 3-Red </syntaxhighlight> A hoard of 5 yellow lizards spawning from pipe 1, on Monk only. <syntaxhighlight lang=""> (Yellow)SU_A10 : 1-Yellow-5 </syntaxhighlight> A Daddy longlegs spawning from pipe 4, but only on easy and normal difficulties. <syntaxhighlight lang=""> (White,Yellow)SU_A10 : 4-Daddy </syntaxhighlight> A very angry white lizard that spawns from pipe 3, on all difficulties. <syntaxhighlight lang=""> SU_A10 : 3-White-{Mean:0.9} </syntaxhighlight> Some enemies require a unique room known as OFFSCREEN. These enemies use special doors that are automatically added to your level to move between rooms. These include vultures, scavengers, leviathans, and miros birds. This example spawns two off screen vultures. <syntaxhighlight lang=""> OFFSCREEN : 0-Vulture-2 </syntaxhighlight> <!--Enemy flags still apply to offscreen enemies. This will spawn a very aggressive KingVulture that will rarely leave the screen if it spots slugcat, but only on Hunter. <syntaxhighlight lang=""> (Red)OFFSCREEN : 0-KingVulture-{Mean:1} </syntaxhighlight> <span id="important-quirks-to-creatures"></span> --><!--King Vultures do not read the info set in their 'flags' ~Bro--> === Important quirks === Enemies may be set to spawn from the same nest pipes. However, do not be surprised if they somehow kill each other offscreen very quickly if you do this. A daddy long legs may have no problems consuming an entire hoard of yellow lizards for example. Enemies will often drag you back to their home nest pipes, but may also choose other pipes they like, even in different rooms. During the end of a cycle, almost every enemy will rush to a nearby nest, if they spawned from it or not. Many creatures that would not intuitively appear to nest in pipes, likely does so, you just never reach them before they spawn in game, or their pipes are well hidden. A direct example of this, is that wandering daddy longlegs spawn from pipes, and return to their pipes before the end of a cycle. This includes the daddies inside Five Pebbles, which makes the area significantly easier once the cycle timer has counted down entirely. It is important to understand various enemy interactions to help you build a cohesive and believable ecosystem for an area. Sandbox mode can help you learn which creature is where on the food chain. As well as looking at the interactions of creatures in other regions. Some creatures have very specific requirements for rooms they inhabit. A very game breaking example, is that big spiders and spitting spiders require the ability to reach every wall in a room in some fashion. By pole, or by invisible ceilings out of the camera. If they cannot, the game will lag very badly due to the spider’s failed pathfinding. Some creatures have a heavier performance impact on the game then others. <!--Sandbox mode can help you learn these, as it will show a notice that “too many of this creature will impact performance” when you begin to place too many.--> <!-- the arena threshold seems somewhat arbitrary in present day--> An example is that more then 4 daddy long legs on screen will often lead to lag. Unfortunate development gets around this problem by using the “stuckDaddy” object, as these daddies do not run wandering path finding checks. All creature types can be configured using the dev tool’s map editor to prefer, avoid, stay or be forbidden inside certain rooms while wandering, using Attraction tool. These spawn entries are simply where they will be created from when the player first enters a region. <span id="the-lineage-system"></span> === The Lineage System === Enemy nests may also be configured to use the lineage system. After being killed, this allows a creature to roll a dice at the end of a cycle, and in a certain percent, respawn as its next entry in the lineage. Due to the format however, you cannot decide how many enemies can spawn from the pipe. So a green lizard cannot turn into a hoard of 3 yellow lizards. Only a single yellow lizard. Enemy flags, and difficulty filters still work however. The format is as follows: <syntaxhighlight lang=""> LINEAGE : ROOM : PIPE : STARTENEMY-PERCENT, NEXTENEMY-PERCENT, FINALENEMY-0 </syntaxhighlight> PERCENT is a value between 0 and 1, and is the percent chance that the enemy will move onto its next form. You may have as many forms as you need. However, it is important to ALWAYS mark the last enemy in the lineage with a 0 percent chance to move on. Rain World will crash the moment it attempts to move to the next enemy in a lineage from the last. ==== Examples ==== A green lizard that spawns from pipe 2, that turns into a blue, and then into a red. With a 5% chance each time. <syntaxhighlight lang=""> LINEAGE : SU_B08 : 2 : Green-0.05, Blue-0.05, Red-0 </syntaxhighlight> A poleplant, with a specific height of 10 blocks, and spawning from pipe 3. That has a 10% chance to turn into a monster kelp <syntaxhighlight lang=""> LINEAGE : SU_A02 : 3 : Mimic-{10}-0.1, TentaclePlant-0 </syntaxhighlight> A empty pipe 3, that has a 1% chance to turn into a monster kelp. <syntaxhighlight lang=""> LINEAGE : SU_B02 : 3 : NONE-0.01, TentaclePlant-0 </syntaxhighlight> Lineage applies to offscreen creatures, as well as difficulties! This example from chimney canopy has a 20% chance to turn a vulture into a king vulture after being killed, but only on normal difficulty. <syntaxhighlight lang=""> (White)LINEAGE : OFFSCREEN : 0 : Vulture-0.2, KingVulture-0 </syntaxhighlight> == Bat Migration Blockages == Bat migration blockages section is bounded by <code>BAT MIGRATION BLOCKAGES</code> and <code>END BAT MIGRATION BLOCKAGES</code> tags. These are used specifically to prevent bat flies from entering a room, or pathing through the region to rooms on the other side of it. These are rarely used. However the room directly after the tutorial area in outskirts is set to be one. The format is simply to list each room line by line between the two tags. There are no unique flags. For the example in Outskirts, bat flies cannot enter room SU_A22 because it is between the tags: <syntaxhighlight lang="">BAT MIGRATION BLOCKAGES SU_A22 END BAT MIGRATION BLOCKAGES </syntaxhighlight> [[Category:Content Mods]] 19426e602182f3252f3465f5a2588538a144cb83 506 468 2023-06-15T05:40:59Z Bro748 31 minor capitalization fix wikitext text/x-wiki {{Cleanup}} [[File:regionFormat.png|thumb|right|alt=regionFormat|regionFormat]] This page describes worldfile format for RW regions. The world_XX.txt file is present in every region Rain World loads, and determines various room settings such as their pipe connections, the spawns of enemies, and specific flags like shelters and gates. NOTE: Creature spawns for the region are generated when you first enter it on a save. Changing room connections or creature spawns in WORLD_XX after that corrupts save data. '''Reset your saveslot or revert your save to before you entered to avoid bugs'''. == Comments == Worldfile format supports comments: if a line starts with double slash (<code>//</code>), it is ignored entirely. == Format == Worldfile contains 2 to 4 sections, each with a different purpose. The start and end of each section is defined by a line containing only <code>SECTIONNAME</code> and <code>END SECTIONNAME</code> The 4 sections are: <code>CONDITIONAL LINKS</code>, <code>ROOMS</code>, <code>CREATURES</code>, and <code>BAT MIGRATION BLOCKAGES</code>. <code>ROOMS</code> and <code>CREATURES</code> are required, the others are optional. A full world file with no contents will look like this: <syntaxhighlight lang=""> CONDITIONAL LINKS //conditional links go here END CONDITIONAL LINKS ROOMS //rooms go here END ROOMS CREATURES //creatures go here END CREATURES BAT MIGRATION BLOCKAGES //migration blockages go here END BAT MIGRATION BLOCKAGES </syntaxhighlight> == Room Connections == Room connections section is bounded by <code>ROOMS</code> and <code>END ROOMS</code> tags. These control which pipe entrance leads to what room, and vice versa. Unique room flags that specify certain attributes about the room (such as if it is a shelter or a gate room) are set here as well. The format is as follows: <syntaxhighlight lang="">ROOM : door0, door1, door2, etc : FLAG </syntaxhighlight> === Examples === A standard room with two room-connecting pipes. These will form the bulk of your region. <syntaxhighlight lang="">TR_T07 : TR_T01, TR_P02 </syntaxhighlight> A standard room, with five doors. However, pipes 1, 2 and 3 have no connection. Each pipe inside a room has a specific number starting from 0. These can be viewed using the [[Dev Tools]]' map tab, or by entering the room with dev tools enabled and pressing M. <syntaxhighlight lang="">TR_W19 : TR_L05, DISCONNECTED, DISCONNECTED, DISCONNECTED, TR_W18 </syntaxhighlight> A shelter. These rooms will often be copied from other regions when you are first learning how to make a region. All vanilla save rooms have a single door. <syntaxhighlight lang="">TR_S01 : TR_P01 : SHELTER </syntaxhighlight> A region gate. Doors on the other side of the gate are set to DISCONNECTED. They will automatically be shown as connected doors at runtime. If you need to show a save room door specifically on the other side of the gate, you can use the ExitSymbolShelter object, in the dev tool’s object tab to change the door symbols as required. <syntaxhighlight lang="">GATE_SS_TR : DISCONNECTED, TR_L07 : GATE </syntaxhighlight> A swarm room allows batflies to spawn in the room, as long as the map contains bat nests. If the room has bat nests but is not marked as a swarm room, those nests will always be inactive. The dev tools map tab provides the options needed to control where they will migrate and rooms they will avoid. <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> A scavenger outpost. Use in conjunction with ScavengerOutpost placedObject to create a scavenger toll. <syntaxhighlight lang="">SU_C02 : SU_A45, SU_A07 : SCAVOUTPOST </syntaxhighlight> === Understanding door connections === [[File:regionFormatConnection.png|thumb|none|alt=regionFormatConnection|regionFormatConnection]] For a door to be properly connected, both ends must point to each other using valid doors. For this example, both rooms will have two doors. Door0 will be on the left, and door1 on the right. Door indices are decided specifically for your room, so be sure to check in game how your doors have been assigned by the [[Level Editor]]. The DT Map tab can also be used to see the links between doors. As in the picture to the right. Properly connected doors will show both lines pointing to the set door on the other end. Doors with incorrect links will point off to the bottom right <!--(A disconnected door will also do this,)--> <!--do fucking what--> and a door connected to another room, but that room has no door back (or lacks enough doors!) will point to the center of the room on the map tab page. <syntaxhighlight lang=""> RG_ROOM1 : DISCONNECTED, RG_ROOM2 </syntaxhighlight> <syntaxhighlight lang=""> RG_ROOM2: RG_ROOM1 </syntaxhighlight> Room1 will have its right hand door connected to Room2. Because of this, we need to use DISCONNECTED as a placeholder for its left hand door, door0. Then set door1 to connect to Room2 Room2 will connect to Room1 using door0. Due to this, we do not need to define the right hand door. It will assume it to be disconnected. === Room Tags === Room tags assign certain properties to rooms depending on what the tag is. Tags are assigned like <syntaxhighlight lang=""> [ROOM] : [CONNECTIONS] : [TAG] </syntaxhighlight> Example: <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> {|class="wikitable" !width="18%"| '''<u>Tag</u>''' !width="81%"| '''<u>Function</u>''' |- | SHELTER | Makes the room a shelter. When there are multiple pipes in the room: the animated door is placed at the bottom right most pipe. |- | ANCIENTSHELTER | Makes the room an Outer Expanse style shelter. |- | GATE | Makes the room a gate. Entrances on the other side of the gate are set to DISCONNECTED, and are shown automatically to be connected. |- | SWARMROOM | Allows batflies to be spawned from batfly hives. |- | PERF_HEAVY | Causes the room to be abstractized quicker when player is not inside, can reduce offscreen performance toll of very large rooms. |- | SCAVOUTPOST | Makes the room into a scavenger outpost. Scavs will spawn here and only let you pass if you have a pearl. The exact outpost location is set by the “ScavengerOutpost” devtools object. |- | SCAVTRADER | Spawns a scavenger merchant into the room. Will trade items with you. The merchant is controlled by the “TradeOutpost” devtools object. |- | NOTRACKERS | Disallows key items from saving in the room (for when the 'Key item tracking' Remix setting is turned on) |- | ARENA | Causes creature spawns in the room to stay in their den until activated by an HRGuard (requires MSC!) |} === Important quirks to rooms and doors === When setting up your region, be sure that you always use your region’s prefix to help each room have a unique name. If not, Rain World will treat repeated names as being other rooms, and even re-use rooms from other region folders entirely. If you don’t use your region prefix, changes made with devtools can also wind up getting saved to unexpected places. To avoid these problems, always prefix your room with its region code, and give them unique names. Multiple pipes in a room may all go to the same room. However, these will all act like a single pipe, and you will not be able to set the specific destination pipes. There are no cases in vanilla Rain World where multiple pipes in the current room lead to the same next room. They will all lead to separate rooms. For example, if you had four pipes leading from one room to another. you would need to create a minimum of three unique rooms for each of the other pipes to act as an interconnection. == Creature Spawns == Creature spawn data section is bounded by <code>CREATURES</code> and <code>END CREATURES</code> tags. Rain World only creates creature spawns when you enter a region for the first time on a save<!--, or after an excessive number of cycles has passed--><!--never heard of it before, may be bogus ~thalber-->. {|class="wikitable" !align="center" width="12%"| '''Lizards''' !align="center" width="25%"| '''Insects''' !align="center" width="13%"| '''Amphibians''' !align="center" width="18%"| '''Flying''' !align="center" width="13%"| '''Plants''' !align="center" width="15%"| '''Other''' |- |align="center"| Pink, PinkLizard |align="center"| Spider |align="center"| Salamander |align="center"| CicadaA |align="center"| PoleMimic, Mimic |align="center"| Scavenger |- |align="center"| Green, GreenLizard |align="center"| Small Centipede, SmallCentipede |align="center"| Leech |align="center"| CicadaB |align="center"| Tentacle, TentaclePlant, Tentacle Plant |align="center"| Lantern Mouse, LanternMouse, Mouse |- |align="center"| Blue, BlueLizard |align="center"| Centipede, Centi, Cent |align="center"| SeaLeech, Sea Leech |align="center"| Vulture |align="center"| |align="center"| Worm, Garbage Worm |- |align="center"| Yellow, YellowLizard |align="center"| Red Centipede, RedCenti, RedCentipede |align="center"| JetFish, Jet Fish |align="center"| KingVulture, King Vulture |align="center"| |align="center"| Miros, MirosBird |- |align="center"| White, WhiteLizard |align="center"| DropBug, DropWig |align="center"| Snail |align="center"| Needle, Needle Worm, BigNeedle, BigNeedleWorm |align="center"| |align="center"| Tube, TubeWorm, Tube Worm |- |align="center"| Black, BlackLizard |align="center"| BigSpider |align="center"| Lev, Leviathan, BigEel, Big Eel |align="center"| SmallNeedleWorm, SmallNeedle |align="center"| |align="center"| Bro, BroLongLegs, BrotherLongLegs |- |align="center"| Cyan, CyanLizard |align="center"| SpitterSpider |align="center"| |align="center"| Centiwing |align="center"| |align="center"| Daddy, DaddyLongLegs |- |align="center"| Red, RedLizard |align="center"| EggBug |align="center"| |align="center"| Cicada* |align="center"| |align="center"| Deer |} {|class="wikitable" !colspan="5"|More Slugcats Creatures |- !align="center" width="12%"| '''Lizards''' !align="center" width="25%"| '''Insects''' !align="center" width="13%"| '''Amphibians''' !align="center" width="18%"| '''Flying''' !align="center" width="28%"| '''Other''' |- |align="center"| Caramel, SpitLizard |align="center"| AquaCenti, AquaCentipede, Aquacenti, Aquapede |align="center"| JungleLeech |align="center"| MirosVulture, Miros Vulture |align="center"| Elite, ScavengerElite, EliteScavenger, Scavenger Elite, Elite Scavenger |- |align="center"| Eel, EelLizard |align="center"| MotherSpider, Mother Spider |align="center"| |align="center"| |align="center"| TerrorLongLegs, Terror |- |align="center"| Strawberry, ZoopLizard |align="center"| FireBug, HellBug |align="center"| |align="center"| |align="center"| HunterDaddy |- |align="center"| Train, TrainLizard |align="center"| Yeek |align="center"| |align="center"| |align="center"| Inspector |} (Multiple names in a single box are interchangeable) (*) Switches between CicadaA and CicadaB) <syntaxhighlight lang=""> //Creature spawns can be specific to a certain character. (White, Yellow) makes something appear for monk and survivor, (Red) only for hunter (character filter)ROOM : PipeNumber-Creature-{optional flags}-Count Additionally, an "X-" prefix can be added to slugcat-specific spawn filters to invert the filter. For example <code>(<u>X-White,Yellow</u>)CC_A07 : 3-Mimic-{18}</code> would make the spawner appear on any slugcats ''except for'' Survivor and Monk. </syntaxhighlight> === Creature Flags === <!--'Flags' is a bad name for this, I think 'tags' would be more appropriate ~bro--> Creature flags set certain properties of the creature. Any flag can be written to any creature, but it will be ignored if they are not one of the following matches: {|class="wikitable" |- !width="8%"| '''Flag''' !width="44%"| '''Description''' !width="23%"| '''Example''' |- | PreCycle || Creature wakes during precycles then go back to bed at normal start of cycle || LM_D02 : 5-Jet Fish-{PreCycle} |- | Ignorecycle || Creature wakes at normal start of cycle and doesn't return to their den at cycle end\night || UW_J01 : 3-Yellow-{Ignorecycle} |- | Night || Creature wakes at start of night || UW_A02 : 2-SpitterSpider-{Night} |- | TentacleImmune || Creature doesn't get grabbed by DLLs, protos, or wormgrass (unused in-game) || RM_F02 : 6-Inspector-{TentacleImmune} |- | Lavasafe || Creature can swim unharmed in lethal water (unused in-game) || HR_R14 : 2-Salamander-{Lavasafe}-3 |- | Voidsea || Turns the creature gold and makes them Lavasafe. Only works on the following creatures: RedLizard, RedCentipede, BigSpider, DaddyLongLegs, BrotherLongLegs, TerrorLongLegs, BigEel, CyanLizard || HR_A04 : 2-RedCentipede-{Voidsea} |- | Winter || Changes the creature's visuals to be more wintery. Only works on the following creatures: BigSpider, SpitterSpider, Yeek, any lizard || (Saint)VS_C04 : 4-Big Spider-3-{Winter} |- | AlternateForm || changes creature's form, does something completely different for each creature. SmallCentipede: turns them green DLL\BLL: turns them to a TLL Vulture\King: makes them albino || LC_longori : 4-Small Centipede-3-{AlternateForm} |- | Mean:<number> || Makes the lizard act more aggressively, with the number determining how aggressive. Only works on Lizards. <number> should be a non-negative value between 0.0 and 1.0 || UW_A09 : 4-White-{Mean:0.7} |- | <number> || Only usable for Pole Plants and Centipedes. Pole Plant: Determines the length in tiles. <number> should be a non-negative integer Centipede: Determines the size. <number> should be a non-negative value between 0.1 and 1.0 || HI_B15 : 3-Centipede-{0.5} HI_A04 : 2-Mimic-{18} |- | Seed:<number> || Creature will always use the specified seed || GW_C02_PAST : 6-Scavenger-{Seed:2837} |- |} === Examples === A single green lizard, spawning from pipe 2, on all difficulties. <syntaxhighlight lang=""> SU_A10 : 2-Green </syntaxhighlight> A single red lizard, spawning from pipe 3, on Hunter only. <syntaxhighlight lang=""> (Red)SU_A10 : 3-Red </syntaxhighlight> A hoard of 5 yellow lizards spawning from pipe 1, on Monk only. <syntaxhighlight lang=""> (Yellow)SU_A10 : 1-Yellow-5 </syntaxhighlight> A Daddy longlegs spawning from pipe 4, but only on easy and normal difficulties. <syntaxhighlight lang=""> (White,Yellow)SU_A10 : 4-Daddy </syntaxhighlight> A very angry white lizard that spawns from pipe 3, on all difficulties. <syntaxhighlight lang=""> SU_A10 : 3-White-{Mean:0.9} </syntaxhighlight> Some enemies require a unique room known as OFFSCREEN. These enemies use special doors that are automatically added to your level to move between rooms. These include vultures, scavengers, leviathans, and miros birds. This example spawns two off screen vultures. <syntaxhighlight lang=""> OFFSCREEN : 0-Vulture-2 </syntaxhighlight> <!--Enemy flags still apply to offscreen enemies. This will spawn a very aggressive KingVulture that will rarely leave the screen if it spots slugcat, but only on Hunter. <syntaxhighlight lang=""> (Red)OFFSCREEN : 0-KingVulture-{Mean:1} </syntaxhighlight> <span id="important-quirks-to-creatures"></span> --><!--King Vultures do not read the info set in their 'flags' ~Bro--> === Important quirks === Enemies may be set to spawn from the same nest pipes. However, do not be surprised if they somehow kill each other offscreen very quickly if you do this. A daddy long legs may have no problems consuming an entire hoard of yellow lizards for example. Enemies will often drag you back to their home nest pipes, but may also choose other pipes they like, even in different rooms. During the end of a cycle, almost every enemy will rush to a nearby nest, if they spawned from it or not. Many creatures that would not intuitively appear to nest in pipes, likely does so, you just never reach them before they spawn in game, or their pipes are well hidden. A direct example of this, is that wandering daddy longlegs spawn from pipes, and return to their pipes before the end of a cycle. This includes the daddies inside Five Pebbles, which makes the area significantly easier once the cycle timer has counted down entirely. It is important to understand various enemy interactions to help you build a cohesive and believable ecosystem for an area. Sandbox mode can help you learn which creature is where on the food chain. As well as looking at the interactions of creatures in other regions. Some creatures have very specific requirements for rooms they inhabit. A very game breaking example, is that big spiders and spitting spiders require the ability to reach every wall in a room in some fashion. By pole, or by invisible ceilings out of the camera. If they cannot, the game will lag very badly due to the spider’s failed pathfinding. Some creatures have a heavier performance impact on the game then others. <!--Sandbox mode can help you learn these, as it will show a notice that “too many of this creature will impact performance” when you begin to place too many.--> <!-- the arena threshold seems somewhat arbitrary in present day--> An example is that more then 4 daddy long legs on screen will often lead to lag. Unfortunate development gets around this problem by using the “stuckDaddy” object, as these daddies do not run wandering path finding checks. All creature types can be configured using the dev tool’s map editor to prefer, avoid, stay or be forbidden inside certain rooms while wandering, using Attraction tool. These spawn entries are simply where they will be created from when the player first enters a region. <span id="the-lineage-system"></span> === The Lineage System === Enemy nests may also be configured to use the lineage system. After being killed, this allows a creature to roll a dice at the end of a cycle, and in a certain percent, respawn as its next entry in the lineage. Due to the format however, you cannot decide how many enemies can spawn from the pipe. So a green lizard cannot turn into a hoard of 3 yellow lizards. Only a single yellow lizard. Enemy flags, and difficulty filters still work however. The format is as follows: <syntaxhighlight lang=""> LINEAGE : ROOM : PIPE : STARTENEMY-PERCENT, NEXTENEMY-PERCENT, FINALENEMY-0 </syntaxhighlight> PERCENT is a value between 0 and 1, and is the percent chance that the enemy will move onto its next form. You may have as many forms as you need. However, it is important to ALWAYS mark the last enemy in the lineage with a 0 percent chance to move on. Rain World will crash the moment it attempts to move to the next enemy in a lineage from the last. ==== Examples ==== A green lizard that spawns from pipe 2, that turns into a blue, and then into a red. With a 5% chance each time. <syntaxhighlight lang=""> LINEAGE : SU_B08 : 2 : Green-0.05, Blue-0.05, Red-0 </syntaxhighlight> A poleplant, with a specific height of 10 blocks, and spawning from pipe 3. That has a 10% chance to turn into a monster kelp <syntaxhighlight lang=""> LINEAGE : SU_A02 : 3 : Mimic-{10}-0.1, TentaclePlant-0 </syntaxhighlight> A empty pipe 3, that has a 1% chance to turn into a monster kelp. <syntaxhighlight lang=""> LINEAGE : SU_B02 : 3 : NONE-0.01, TentaclePlant-0 </syntaxhighlight> Lineage applies to offscreen creatures, as well as difficulties! This example from chimney canopy has a 20% chance to turn a vulture into a king vulture after being killed, but only on normal difficulty. <syntaxhighlight lang=""> (White)LINEAGE : OFFSCREEN : 0 : Vulture-0.2, KingVulture-0 </syntaxhighlight> == Bat Migration Blockages == Bat migration blockages section is bounded by <code>BAT MIGRATION BLOCKAGES</code> and <code>END BAT MIGRATION BLOCKAGES</code> tags. These are used specifically to prevent bat flies from entering a room, or pathing through the region to rooms on the other side of it. These are rarely used. However the room directly after the tutorial area in outskirts is set to be one. The format is simply to list each room line by line between the two tags. There are no unique flags. For the example in Outskirts, bat flies cannot enter room SU_A22 because it is between the tags: <syntaxhighlight lang="">BAT MIGRATION BLOCKAGES SU_A22 END BAT MIGRATION BLOCKAGES </syntaxhighlight> [[Category:Content Mods]] 6c995d7df99e191889e1d6609095816bcb07ccc5 507 506 2023-06-19T05:28:28Z Bro748 31 /* Creature Spawns */ wikitext text/x-wiki {{Cleanup}} [[File:regionFormat.png|thumb|right|alt=regionFormat|regionFormat]] This page describes worldfile format for RW regions. The world_XX.txt file is present in every region Rain World loads, and determines various room settings such as their pipe connections, the spawns of enemies, and specific flags like shelters and gates. NOTE: Creature spawns for the region are generated when you first enter it on a save. Changing room connections or creature spawns in WORLD_XX after that corrupts save data. '''Reset your saveslot or revert your save to before you entered to avoid bugs'''. == Comments == Worldfile format supports comments: if a line starts with double slash (<code>//</code>), it is ignored entirely. == Format == Worldfile contains 2 to 4 sections, each with a different purpose. The start and end of each section is defined by a line containing only <code>SECTIONNAME</code> and <code>END SECTIONNAME</code> The 4 sections are: <code>CONDITIONAL LINKS</code>, <code>ROOMS</code>, <code>CREATURES</code>, and <code>BAT MIGRATION BLOCKAGES</code>. <code>ROOMS</code> and <code>CREATURES</code> are required, the others are optional. A full world file with no contents will look like this: <syntaxhighlight lang=""> CONDITIONAL LINKS //conditional links go here END CONDITIONAL LINKS ROOMS //rooms go here END ROOMS CREATURES //creatures go here END CREATURES BAT MIGRATION BLOCKAGES //migration blockages go here END BAT MIGRATION BLOCKAGES </syntaxhighlight> == Room Connections == Room connections section is bounded by <code>ROOMS</code> and <code>END ROOMS</code> tags. These control which pipe entrance leads to what room, and vice versa. Unique room flags that specify certain attributes about the room (such as if it is a shelter or a gate room) are set here as well. The format is as follows: <syntaxhighlight lang="">ROOM : door0, door1, door2, etc : FLAG </syntaxhighlight> === Examples === A standard room with two room-connecting pipes. These will form the bulk of your region. <syntaxhighlight lang="">TR_T07 : TR_T01, TR_P02 </syntaxhighlight> A standard room, with five doors. However, pipes 1, 2 and 3 have no connection. Each pipe inside a room has a specific number starting from 0. These can be viewed using the [[Dev Tools]]' map tab, or by entering the room with dev tools enabled and pressing M. <syntaxhighlight lang="">TR_W19 : TR_L05, DISCONNECTED, DISCONNECTED, DISCONNECTED, TR_W18 </syntaxhighlight> A shelter. These rooms will often be copied from other regions when you are first learning how to make a region. All vanilla save rooms have a single door. <syntaxhighlight lang="">TR_S01 : TR_P01 : SHELTER </syntaxhighlight> A region gate. Doors on the other side of the gate are set to DISCONNECTED. They will automatically be shown as connected doors at runtime. If you need to show a save room door specifically on the other side of the gate, you can use the ExitSymbolShelter object, in the dev tool’s object tab to change the door symbols as required. <syntaxhighlight lang="">GATE_SS_TR : DISCONNECTED, TR_L07 : GATE </syntaxhighlight> A swarm room allows batflies to spawn in the room, as long as the map contains bat nests. If the room has bat nests but is not marked as a swarm room, those nests will always be inactive. The dev tools map tab provides the options needed to control where they will migrate and rooms they will avoid. <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> A scavenger outpost. Use in conjunction with ScavengerOutpost placedObject to create a scavenger toll. <syntaxhighlight lang="">SU_C02 : SU_A45, SU_A07 : SCAVOUTPOST </syntaxhighlight> === Understanding door connections === [[File:regionFormatConnection.png|thumb|none|alt=regionFormatConnection|regionFormatConnection]] For a door to be properly connected, both ends must point to each other using valid doors. For this example, both rooms will have two doors. Door0 will be on the left, and door1 on the right. Door indices are decided specifically for your room, so be sure to check in game how your doors have been assigned by the [[Level Editor]]. The DT Map tab can also be used to see the links between doors. As in the picture to the right. Properly connected doors will show both lines pointing to the set door on the other end. Doors with incorrect links will point off to the bottom right <!--(A disconnected door will also do this,)--> <!--do fucking what--> and a door connected to another room, but that room has no door back (or lacks enough doors!) will point to the center of the room on the map tab page. <syntaxhighlight lang=""> RG_ROOM1 : DISCONNECTED, RG_ROOM2 </syntaxhighlight> <syntaxhighlight lang=""> RG_ROOM2: RG_ROOM1 </syntaxhighlight> Room1 will have its right hand door connected to Room2. Because of this, we need to use DISCONNECTED as a placeholder for its left hand door, door0. Then set door1 to connect to Room2 Room2 will connect to Room1 using door0. Due to this, we do not need to define the right hand door. It will assume it to be disconnected. === Room Tags === Room tags assign certain properties to rooms depending on what the tag is. Tags are assigned like <syntaxhighlight lang=""> [ROOM] : [CONNECTIONS] : [TAG] </syntaxhighlight> Example: <syntaxhighlight lang="">SU_A06 : SU_A39, SU_A36, SU_A38 : SWARMROOM </syntaxhighlight> {|class="wikitable" !width="18%"| '''<u>Tag</u>''' !width="81%"| '''<u>Function</u>''' |- | SHELTER | Makes the room a shelter. When there are multiple pipes in the room: the animated door is placed at the bottom right most pipe. |- | ANCIENTSHELTER | Makes the room an Outer Expanse style shelter. |- | GATE | Makes the room a gate. Entrances on the other side of the gate are set to DISCONNECTED, and are shown automatically to be connected. |- | SWARMROOM | Allows batflies to be spawned from batfly hives. |- | PERF_HEAVY | Causes the room to be abstractized quicker when player is not inside, can reduce offscreen performance toll of very large rooms. |- | SCAVOUTPOST | Makes the room into a scavenger outpost. Scavs will spawn here and only let you pass if you have a pearl. The exact outpost location is set by the “ScavengerOutpost” devtools object. |- | SCAVTRADER | Spawns a scavenger merchant into the room. Will trade items with you. The merchant is controlled by the “TradeOutpost” devtools object. |- | NOTRACKERS | Disallows key items from saving in the room (for when the 'Key item tracking' Remix setting is turned on) |- | ARENA | Causes creature spawns in the room to stay in their den until activated by an HRGuard (requires MSC!) |} === Important quirks to rooms and doors === When setting up your region, be sure that you always use your region’s prefix to help each room have a unique name. If not, Rain World will treat repeated names as being other rooms, and even re-use rooms from other region folders entirely. If you don’t use your region prefix, changes made with devtools can also wind up getting saved to unexpected places. To avoid these problems, always prefix your room with its region code, and give them unique names. Multiple pipes in a room may all go to the same room. However, these will all act like a single pipe, and you will not be able to set the specific destination pipes. There are no cases in vanilla Rain World where multiple pipes in the current room lead to the same next room. They will all lead to separate rooms. For example, if you had four pipes leading from one room to another. you would need to create a minimum of three unique rooms for each of the other pipes to act as an interconnection. == Creature Spawns == Creature spawn data section is bounded by <code>CREATURES</code> and <code>END CREATURES</code> tags. Rain World only creates creature spawns when you enter a region for the first time on a save<!--, or after an excessive number of cycles has passed--><!--never heard of it before, may be bogus ~thalber-->. Every creature has an internal codename, and many of them have aliases which can be used interchangeably in the world file. The table below contains all aliases in the same box, with the real name being bolded. First in the box is the alias the vanilla game uses most often. {|class="wikitable" !align="center" width="12%"| '''Lizards''' !align="center" width="25%"| '''Insects''' !align="center" width="13%"| '''Amphibians''' !align="center" width="18%"| '''Flying''' !align="center" width="13%"| '''Plants''' !align="center" width="15%"| '''Other''' |- |align="center"| Pink, '''PinkLizard''' |align="center"| '''Spider''' |align="center"| '''Salamander''' |align="center"| '''CicadaA''' |align="center"| '''PoleMimic''', Mimic |align="center"| '''Scavenger''' |- |align="center"| Green, '''GreenLizard''' |align="center"| '''SmallCentipede''' |align="center"| '''Leech''' |align="center"| '''CicadaB''' |align="center"| Tentacle, '''TentaclePlant''', Tentacle Plant |align="center"| Lantern Mouse, '''LanternMouse''', Mouse |- |align="center"| Blue, '''BlueLizard''' |align="center"| '''Centipede''', Centi, Cent |align="center"| '''SeaLeech''', Sea Leech |align="center"| '''Vulture''' |align="center"| |align="center"| Worm, Garbage Worm, '''GarbageWorm''' |- |align="center"| Yellow, '''YellowLizard''' |align="center"| Red Centipede, '''RedCentipede''', RedCenti, Red Centi |align="center"| '''JetFish''', Jet Fish |align="center"| '''KingVulture''', King Vulture |align="center"| |align="center"| Miros, Miros Bird, '''MirosBird''' |- |align="center"| White, '''WhiteLizard''' |align="center"| '''DropBug''', Drop Bug, DropWig, Drop Wig |align="center"| '''Snail''' |align="center"| Needle, Needle Worm, BigNeedle, Big Needle, '''BigNeedleWorm''' |align="center"| |align="center"| Tube, '''TubeWorm''', Tube Worm |- |align="center"| Black, '''BlackLizard''' |align="center"| '''BigSpider''', Big Spider |align="center"| Lev, Leviathan, '''BigEel''', Big Eel |align="center"| '''SmallNeedleWorm''', SmallNeedle, Small Needle |align="center"| |align="center"| Bro, BroLongLegs, Bro Long Legs, '''BrotherLongLegs''' |- |align="center"| Cyan, '''CyanLizard''' |align="center"| '''SpitterSpider''', Spitter Spider |align="center"| |align="center"| '''Centiwing''' |align="center"| |align="center"| Daddy, '''DaddyLongLegs''', Daddy Long Legs |- |align="center"| Red, '''RedLizard''' |align="center"| '''EggBug''', Egg Bug |align="center"| |align="center"| Cicada* |align="center"| |align="center"| '''Deer''' |} {|class="wikitable" !colspan="5"|More Slugcats Creatures |- !align="center" width="12%"| '''Lizards''' !align="center" width="25%"| '''Insects''' !align="center" width="13%"| '''Amphibians''' !align="center" width="18%"| '''Flying''' !align="center" width="28%"| '''Other''' |- |align="center"| Caramel, '''SpitLizard''' |align="center"| '''AquaCenti''', Aqua Centi, AquaCentipede, Aqua Centipede, Aquapede |align="center"| '''JungleLeech''' |align="center"| '''MirosVulture''', Miros Vulture |align="center"| Elite, '''ScavengerElite''', Scavenger Elite, EliteScavenger, Elite Scavenger |- |align="center"| Eel, '''EelLizard''' |align="center"| '''MotherSpider''', Mother Spider |align="center"| |align="center"| |align="center"| '''TerrorLongLegs''', Terror Long Legs, Terror, Mother, MotherLongLegs, Mother Long Legs |- |align="center"| Strawberry, '''ZoopLizard''' |align="center"| '''FireBug''', Fire Bug, HellBug, Hell Bug |align="center"| |align="center"| |align="center"| '''HunterDaddy''', Hunter Daddy, Hunter |- |align="center"| Train, '''TrainLizard''' |align="center"| '''Yeek''' |align="center"| |align="center"| |align="center"| '''Inspector''' |} (*) Switches between CicadaA and CicadaB) Creature spawns can be specific to a certain character. (White, Yellow) makes something appear for monk and survivor, (Red) only for hunter <code>(character filter)ROOM : PipeNumber-Creature-{optional flags}-Count</code> Additionally, an "X-" prefix can be added to slugcat-specific spawn filters to invert the filter. For example <code>(<u>X-White,Yellow</u>)CC_A07 : 3-Mimic-{18}</code> would make the spawner appear on any slugcats ''except for'' Survivor and Monk. === Creature Flags === <!--'Flags' is a bad name for this, I think 'tags' would be more appropriate ~bro--> Creature flags set certain properties of the creature. Any flag can be written to any creature, but it will be ignored if they are not one of the following matches: {|class="wikitable" |- !width="8%"| '''Flag''' !width="44%"| '''Description''' !width="23%"| '''Example''' |- | PreCycle || Creature wakes during precycles then go back to bed at normal start of cycle || LM_D02 : 5-Jet Fish-{PreCycle} |- | Ignorecycle || Creature wakes at normal start of cycle and doesn't return to their den at cycle end\night || UW_J01 : 3-Yellow-{Ignorecycle} |- | Night || Creature wakes at start of night || UW_A02 : 2-SpitterSpider-{Night} |- | TentacleImmune || Creature doesn't get grabbed by DLLs, protos, or wormgrass (unused in-game) || RM_F02 : 6-Inspector-{TentacleImmune} |- | Lavasafe || Creature can swim unharmed in lethal water (unused in-game) || HR_R14 : 2-Salamander-{Lavasafe}-3 |- | Voidsea || Turns the creature gold and makes them Lavasafe. Only works on the following creatures: RedLizard, RedCentipede, BigSpider, DaddyLongLegs, BrotherLongLegs, TerrorLongLegs, BigEel, CyanLizard || HR_A04 : 2-RedCentipede-{Voidsea} |- | Winter || Changes the creature's visuals to be more wintery. Only works on the following creatures: BigSpider, SpitterSpider, Yeek, any lizard || (Saint)VS_C04 : 4-Big Spider-3-{Winter} |- | AlternateForm || changes creature's form, does something completely different for each creature. SmallCentipede: turns them green DLL\BLL: turns them to a TLL Vulture\King: makes them albino || LC_longori : 4-Small Centipede-3-{AlternateForm} |- | Mean:<number> || Makes the lizard act more aggressively, with the number determining how aggressive. Only works on Lizards. <number> should be a non-negative value between 0.0 and 1.0 || UW_A09 : 4-White-{Mean:0.7} |- | <number> || Only usable for Pole Plants and Centipedes. Pole Plant: Determines the length in tiles. <number> should be a non-negative integer Centipede: Determines the size. <number> should be a non-negative value between 0.1 and 1.0 || HI_B15 : 3-Centipede-{0.5} HI_A04 : 2-Mimic-{18} |- | Seed:<number> || Creature will always use the specified seed || GW_C02_PAST : 6-Scavenger-{Seed:2837} |- |} === Examples === A single green lizard, spawning from pipe 2, on all difficulties. <syntaxhighlight lang=""> SU_A10 : 2-Green </syntaxhighlight> A single red lizard, spawning from pipe 3, on Hunter only. <syntaxhighlight lang=""> (Red)SU_A10 : 3-Red </syntaxhighlight> A hoard of 5 yellow lizards spawning from pipe 1, on Monk only. <syntaxhighlight lang=""> (Yellow)SU_A10 : 1-Yellow-5 </syntaxhighlight> A Daddy longlegs spawning from pipe 4, but only on easy and normal difficulties. <syntaxhighlight lang=""> (White,Yellow)SU_A10 : 4-Daddy </syntaxhighlight> A very angry white lizard that spawns from pipe 3, on all difficulties. <syntaxhighlight lang=""> SU_A10 : 3-White-{Mean:0.9} </syntaxhighlight> Some enemies require a unique room known as OFFSCREEN. These enemies use special doors that are automatically added to your level to move between rooms. These include vultures, scavengers, leviathans, and miros birds. This example spawns two off screen vultures. <syntaxhighlight lang=""> OFFSCREEN : 0-Vulture-2 </syntaxhighlight> <!--Enemy flags still apply to offscreen enemies. This will spawn a very aggressive KingVulture that will rarely leave the screen if it spots slugcat, but only on Hunter. <syntaxhighlight lang=""> (Red)OFFSCREEN : 0-KingVulture-{Mean:1} </syntaxhighlight> <span id="important-quirks-to-creatures"></span> --><!--King Vultures do not read the info set in their 'flags' ~Bro--> === Important quirks === Enemies may be set to spawn from the same nest pipes. However, do not be surprised if they somehow kill each other offscreen very quickly if you do this. A daddy long legs may have no problems consuming an entire hoard of yellow lizards for example. Enemies will often drag you back to their home nest pipes, but may also choose other pipes they like, even in different rooms. During the end of a cycle, almost every enemy will rush to a nearby nest, if they spawned from it or not. Many creatures that would not intuitively appear to nest in pipes, likely does so, you just never reach them before they spawn in game, or their pipes are well hidden. A direct example of this, is that wandering daddy longlegs spawn from pipes, and return to their pipes before the end of a cycle. This includes the daddies inside Five Pebbles, which makes the area significantly easier once the cycle timer has counted down entirely. It is important to understand various enemy interactions to help you build a cohesive and believable ecosystem for an area. Sandbox mode can help you learn which creature is where on the food chain. As well as looking at the interactions of creatures in other regions. Some creatures have very specific requirements for rooms they inhabit. A very game breaking example, is that big spiders and spitting spiders require the ability to reach every wall in a room in some fashion. By pole, or by invisible ceilings out of the camera. If they cannot, the game will lag very badly due to the spider’s failed pathfinding. Some creatures have a heavier performance impact on the game then others. <!--Sandbox mode can help you learn these, as it will show a notice that “too many of this creature will impact performance” when you begin to place too many.--> <!-- the arena threshold seems somewhat arbitrary in present day--> An example is that more then 4 daddy long legs on screen will often lead to lag. Unfortunate development gets around this problem by using the “stuckDaddy” object, as these daddies do not run wandering path finding checks. All creature types can be configured using the dev tool’s map editor to prefer, avoid, stay or be forbidden inside certain rooms while wandering, using Attraction tool. These spawn entries are simply where they will be created from when the player first enters a region. <span id="the-lineage-system"></span> === The Lineage System === Enemy nests may also be configured to use the lineage system. After being killed, this allows a creature to roll a dice at the end of a cycle, and in a certain percent, respawn as its next entry in the lineage. Due to the format however, you cannot decide how many enemies can spawn from the pipe. So a green lizard cannot turn into a hoard of 3 yellow lizards. Only a single yellow lizard. Enemy flags, and difficulty filters still work however. The format is as follows: <syntaxhighlight lang=""> LINEAGE : ROOM : PIPE : STARTENEMY-PERCENT, NEXTENEMY-PERCENT, FINALENEMY-0 </syntaxhighlight> PERCENT is a value between 0 and 1, and is the percent chance that the enemy will move onto its next form. You may have as many forms as you need. However, it is important to ALWAYS mark the last enemy in the lineage with a 0 percent chance to move on. Rain World will crash the moment it attempts to move to the next enemy in a lineage from the last. ==== Examples ==== A green lizard that spawns from pipe 2, that turns into a blue, and then into a red. With a 5% chance each time. <syntaxhighlight lang=""> LINEAGE : SU_B08 : 2 : Green-0.05, Blue-0.05, Red-0 </syntaxhighlight> A poleplant, with a specific height of 10 blocks, and spawning from pipe 3. That has a 10% chance to turn into a monster kelp <syntaxhighlight lang=""> LINEAGE : SU_A02 : 3 : Mimic-{10}-0.1, TentaclePlant-0 </syntaxhighlight> A empty pipe 3, that has a 1% chance to turn into a monster kelp. <syntaxhighlight lang=""> LINEAGE : SU_B02 : 3 : NONE-0.01, TentaclePlant-0 </syntaxhighlight> Lineage applies to offscreen creatures, as well as difficulties! This example from chimney canopy has a 20% chance to turn a vulture into a king vulture after being killed, but only on normal difficulty. <syntaxhighlight lang=""> (White)LINEAGE : OFFSCREEN : 0 : Vulture-0.2, KingVulture-0 </syntaxhighlight> == Bat Migration Blockages == Bat migration blockages section is bounded by <code>BAT MIGRATION BLOCKAGES</code> and <code>END BAT MIGRATION BLOCKAGES</code> tags. These are used specifically to prevent bat flies from entering a room, or pathing through the region to rooms on the other side of it. These are rarely used. However the room directly after the tutorial area in outskirts is set to be one. The format is simply to list each room line by line between the two tags. There are no unique flags. For the example in Outskirts, bat flies cannot enter room SU_A22 because it is between the tags: <syntaxhighlight lang="">BAT MIGRATION BLOCKAGES SU_A22 END BAT MIGRATION BLOCKAGES </syntaxhighlight> [[Category:Content Mods]] 43d2ead2fe8b4a9bdfd6831eea9e0063dd069faa Rain World Code Structure/LOD 0 192 469 2023-04-17T10:24:39Z Thalber 3 init wikitext text/x-wiki Rain World uses two LOD ([https://en.wikipedia.org/wiki/Level_of_detail_(computer_graphics) Level Of Detail]) modes for entities in main loop: * Realized - high detail, updates every frame, physical interactions are fully rendered. Used in rooms close to player. * Abstract - low detail, each entity receives updates every several frames, physics interactions and detailed creature movements are replaced with simpler probabilistic interaction models (can be thought of as dice rolls). Default state. LOD level is selected on per-room basis, and is passed down on all entities in room. When in a realized room, abstract LOD entities (base class for these is (technically) AbstractWorldEntity and (practically) AbstractPhysicalObject) persist, but a realized version is attached to them until they abstractize again. All data not explicitly stored in abstract object is lost when an entity abstracts. This affects, for example, wolf spider revive mechanic: wolf spiders store a representation of one other spider they are willing to revive when they have body contact (<code>reviveBuddy</code> field in <code>BigSpiderAI</code>), and forget it when they leave realized space. == Abstract layer == Rooms are <code>AbstractRoom</code>, and all entities are <code>AbstractWorldEntity</code>. '''AbstractWorldEntity'''`s one child class is '''AbstractPhysicalObject''', and AbstractWorldEntity is never instantiated in vanilla (so in practice everything in abstract world is an AbstractPhysicalObject). {| class="wikitable sortable" |+ AbstractWorldEntity useful members |- ! Member !! Kind !! Description |- | Abstractize || method || Called when entity should switch from realized to abstract state. Does nothing on this class (implementation is on AbstractPhysicalObject) |- | Destroy || method || Marks entity for deletion at the end{{Cn}} of the frame. |- | IsEnteringDen || method || Called when entering a creature den (not player shelter). |- | IsExitingDen || method || Called when exiting a creature den (not player shelter). |- | Update || method || Called every few frames. Argument <code>time</code> tells it how many frames have passed since last update. |- | Room || property || Returns abstract room this entity is in. |- | ID || field || Unique identifier of the entity. Used for generating properties of many things (for example, each time a creature with individual cosmetic variations, such as a Scavenger, is realized, it uses its ID as a seed to deterministically generate these stats) |- | InDen || field || Whether the entity is currently inside a creature den |- | pos || field || A <code>WorldCoordinate</code> of the creature. Stores room index and tile position of the entity. |- | slatedForDeletion || field || Whether entity should be deleted next abstract update |- | world || field || Reference to the World object entity belongs to |} {| class="wikitable sortable" |+ AbstractPhysicalObject useful members |- ! Member !! Kind !! Description |- | ChangeRooms || method || Moves instance from one room to another |- | GetAllConnectedObjects || method || Returns a list of all objects the instance is connected to |- | LoseAllStuckObjects || method || Unsticks all connected objects from itself |- | Move || method || Moves entity from one tile to another |- | Realize || method || Creates an appropriate realized object attached to this entity, without placing it in current room. Probably not for direct use{{Cn}} |- | RealizeInRoom || method || Creates an appropriate realized object attached to this entity, and adds it to current room |- | ToString || method || Returns a serialization string for this entity |- | destroyOnAbstraction || field || Whether this object should be destroyed when it exits realized space |- | realizedObject || field || Realized part of the entity. Null while in abstract LOD |- | stuckObjects || field || List of other objects that have been stuck to this one |- | tracker || field || An object carrying data the game uses for respawning key items, such as pearls or hunter's neuron. Null for most entities |- | type || field || An ExtEnum telling what kind of object this is (a spear, a neuron, a creature etc) |- || unrecognizedAttributes || field || '''An array of arbitrary strings attached to the instance. Contains data the game cannot parse. Saved appropriately, can be used by mods to attach data to AbstractPhysicalObjects''' |} == Realized layer == {{todo}} Rooms are <code>Room</code> (always attached to an instance of AbstractRoom), basic entities are <code>UpdatableAndDeletable</code>, AbstractPhysicalObject realized versions are <code>PhysicalObject</code>. Unlike with abstract LOD, '''UpdatableAndDeletable''' has children that are not '''PhysicalObject'''s (cosmetic sprites, background elements, etc). UpdatableAndDeletable may be shortened to UAD in this section. {| class="wikitable sortable" |+ UpdatableAndDeletable members |- ! Member !! Kind !! Description |- | Destroy || method || Marks UAD to be deleted at the end{{Cn}} of the frame |- | Update || method || Called every physics tick (40 TPS) when game is not paused |- | PausedUpdate || method || Called every physics tick when game is paused |- | RemoveFromRoom || method || Removes instance from room |- | slatedForDeletion || property || Indicates whether UAD will be deleted by the end{{Cn}} of the frame |- | room || field || Room this UAD belongs to |} {| class="wikitable sortable" |+ PhysicalObject members |- ! Member !! Kind !! Description |- | |} 3272257f02f8649eb6692dca5a7c4b55d653dfe8 471 469 2023-04-17T15:38:38Z Thalber 3 wikitext text/x-wiki {{todo|target=page}} Rain World uses two LOD ([https://en.wikipedia.org/wiki/Level_of_detail_(computer_graphics) Level Of Detail]) modes for entities in main loop: * Realized - high detail, updates every frame, physical interactions are fully rendered. Used in rooms close to player. * Abstract - low detail, each entity receives updates every several frames, physics interactions and detailed creature movements are replaced with simpler probabilistic interaction models (can be thought of as dice rolls). Default state. LOD level is selected on per-room basis, and is passed down on all entities in room. When in a realized room, abstract LOD entities (base class for these is (technically) AbstractWorldEntity and (practically) AbstractPhysicalObject) persist, but a realized version is attached to them until they abstractize again. All data not explicitly stored in abstract object is lost when an entity abstracts. This affects, for example, wolf spider revive mechanic: wolf spiders store a representation of one other spider they are willing to revive when they have body contact (<code>reviveBuddy</code> field in <code>BigSpiderAI</code>), and forget it when they leave realized space. == Abstract layer == Rooms are <code>AbstractRoom</code>, and all entities are <code>AbstractWorldEntity</code>. '''AbstractWorldEntity'''`s one child class is '''AbstractPhysicalObject''', and AbstractWorldEntity is never instantiated in vanilla (so in practice everything in abstract world is an AbstractPhysicalObject). {| class="wikitable sortable" |+ AbstractWorldEntity useful members |- ! Member !! Kind !! Description |- | Abstractize || method || Called when entity should switch from realized to abstract state. Does nothing on this class (implementation is on AbstractPhysicalObject) |- | Destroy || method || Marks entity for deletion at the end{{Cn}} of the frame. |- | IsEnteringDen || method || Called when entering a creature den (not player shelter). |- | IsExitingDen || method || Called when exiting a creature den (not player shelter). |- | Update || method || Called every few frames. Argument <code>time</code> tells it how many frames have passed since last update. |- | Room || property || Returns abstract room this entity is in. |- | ID || field || Unique identifier of the entity. Used for generating properties of many things (for example, each time a creature with individual cosmetic variations, such as a Scavenger, is realized, it uses its ID as a seed to deterministically generate these stats) |- | InDen || field || Whether the entity is currently inside a creature den |- | pos || field || A <code>WorldCoordinate</code> of the creature. Stores room index and tile position of the entity. |- | slatedForDeletion || field || Whether entity should be deleted next abstract update |- | world || field || Reference to the World object entity belongs to |} {| class="wikitable sortable" |+ AbstractPhysicalObject useful members |- ! Member !! Kind !! Description |- | ChangeRooms || method || Moves instance from one room to another |- | GetAllConnectedObjects || method || Returns a list of all objects the instance is connected to |- | LoseAllStuckObjects || method || Unsticks all connected objects from itself |- | Move || method || Moves entity from one tile to another |- | Realize || method || Creates an appropriate realized object attached to this entity, without placing it in current room. Probably not for direct use{{Cn}} |- | RealizeInRoom || method || Creates an appropriate realized object attached to this entity, and adds it to current room |- | ToString || method || Returns a serialization string for this entity |- | destroyOnAbstraction || field || Whether this object should be destroyed when it exits realized space |- | realizedObject || field || Realized part of the entity. Null while in abstract LOD |- | stuckObjects || field || List of other objects that have been stuck to this one |- | tracker || field || An object carrying data the game uses for respawning key items, such as pearls or hunter's neuron. Null for most entities |- | type || field || An ExtEnum telling what kind of object this is (a spear, a neuron, a creature etc) |- || unrecognizedAttributes || field || '''An array of arbitrary strings attached to the instance. Contains data the game cannot parse. Saved appropriately, can be used by mods to attach data to AbstractPhysicalObjects''' |} == Realized layer == {{todo}} Rooms are <code>Room</code> (always attached to an instance of AbstractRoom), basic entities are <code>UpdatableAndDeletable</code>, AbstractPhysicalObject realized versions are <code>PhysicalObject</code>. Unlike with abstract LOD, '''UpdatableAndDeletable''' has children that are not '''PhysicalObject'''s (cosmetic sprites, background elements, etc). UpdatableAndDeletable may be shortened to UAD in this section. === UpdatableAndDeletable === Basic room entity. {| class="wikitable sortable" |+ UpdatableAndDeletable members |- ! Member !! Kind !! Description |- | Destroy || method || Marks UAD to be deleted at the end{{Cn}} of the frame |- | Update || method || Called every physics tick (40 TPS) when game is not paused |- | PausedUpdate || method || Called every physics tick when game is paused |- | RemoveFromRoom || method || Removes instance from room |- | slatedForDeletion || property || Indicates whether UAD will be deleted by the end{{Cn}} of the frame |- | room || field || Room this UAD belongs to |} <!-- todo: add interface descriptions? no wait that's in uad inheritance --> === PhysicalObject === All PhysicalObjects are composed of BodyChunks. Every BodyChunk has circular collision. Each PhysicalObject begins to a collision layer, of which there are 3 (0, 1 and 2). {| class="wikitable sortable" |+ PhysicalObject useful members |- ! Member !! Kind !! Description |- | ChangeCollisionLayer || method || Sets collision layer of instance |- | collisionLayer || field || Current collision layer. Invalid value will produce error on trying to add into room |- | Collide || method || Called every time instance touches another |- | TerrainImpact || method || Called every time instance hits terrain |- | Grabbed || method || Called every time instance is grabbed by a creature |- | HitByWeapon || method || Called every time instance is hit by a throwable weapon (such as a Spear). Applying damage to creatures is handled by the weapon itself, outside of this method |- | HitByExplosion || method || Called every time instance is hit by an explosion. Applying damage to creatures is handled by the explosion itself, outside of this method |- | graphicsModule || property || Helper object that manages the instance's visuals. Not all PhysicalObject children have graphics modules (for example, most creatures do, but weapons don't) |- | InitiateGraphicsModule || method || Called when room containing instance becomes visible. Intended behavior: filling graphicsModule field (without adding it to room). |- | GraphicsModuleUpdated || method || Called every time after the Room attempts to update its graphics module |- | DisposeGraphicsModule || method || Called when room containing instance becomes no longer visible. Detaches and destroys graphics module |- | NewRoom || method || Called when instance is added to a new room{{Cn}} |- | PlaceInRoom || method || Adds instance to a selected room |- | bodyChunks || property || An array of BodyChunk objects composing instance's body. Should always be instantiated by the constructor |- | appendages || field || A list of appendages this instance has. Appendages don't directly collide with body chunks, but still collide with terrain and can be hit by weapons{{Cn}}. Should always be instantiated by the constructor. Instances with appendages should implement <code>PhysicalObject.IHaveAppendages</code> |- | bodyChunkConnections || field || Array of objects determining how different chunks are physically tied to each other. Should always be instantiated by the constructor (empty if no chunk connections) |- | Gravity || property || Gravity of object. Calculated by multiplying room-wide gravity with instance's personal g value. Setter just sets g |- | g || field || Instance's personal gravity multiplier |- | airFriction || property || Air friction determines how much instance's velocity decays every frame. Applies when out of water or partially submerged. '''IMPORTANT''': Each frame chunk velocity is ''multiplied'' by friction value, so the expected value is in range between 0 and 1, usually very close to 1. If you set this to more than 1.0f, the object will accelerate exponentially! |- | waterFriction || property || Air friction determines how much instance's velocity decays every frame. Applies when out of water or partially submerged. '''IMPORTANT''': Each frame chunk velocity is ''multiplied'' by friction value, so the expected value is in range between 0 and 1, usually very close to 1. If you set this to more than 1.0f, the object will accelerate exponentially! |- | buoyancy || property || How much water pushes the object out. 0f means no pushout (instance stays suspended), negative values make instance sink, positive make it float to the surface. |- | GoThroughFloors || property || Whether instance should fall through platforms. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithObjects || property || Whether instance should collide with other objects on the same physics layer. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithTerrain || property || Whether instance should collide with solid terrain tiles. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithSlopes || property || Whether instance should collide with slope terrain tiles. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | submersion || property || Averaged submersion of all chunks |- | VisibilityBonus || property || Value used by AI on visual contact to roll for a creature spotting the instance. Positive values mean increased likelihood, negative means reduced likelihood |- | grabbedBy || field || List of things that are grabbing instance |} 6de354e103668744ea99cf4a523447e213e925ca 473 471 2023-04-17T15:47:04Z Thalber 3 prepare to split wikitext text/x-wiki {{todo|target=page}} Rain World uses two LOD ([https://en.wikipedia.org/wiki/Level_of_detail_(computer_graphics) Level Of Detail]) modes for entities in main loop: * Realized - high detail, updates every frame, physical interactions are fully rendered. Used in rooms close to player. * Abstract - low detail, each entity receives updates every several frames, physics interactions and detailed creature movements are replaced with simpler probabilistic interaction models (can be thought of as dice rolls). Default state. LOD level is selected on per-room basis, and is passed down on all entities in room. When in a realized room, abstract LOD entities (base class for these is (technically) AbstractWorldEntity and (practically) AbstractPhysicalObject) persist, but a realized version is attached to them until they abstractize again. All data not explicitly stored in abstract object is lost when an entity abstracts. This affects, for example, wolf spider revive mechanic: wolf spiders store a representation of one other spider they are willing to revive when they have body contact (<code>reviveBuddy</code> field in <code>BigSpiderAI</code>), and forget it when they leave realized space. == Abstract layer == Rooms are <code>AbstractRoom</code>, and all entities are <code>AbstractWorldEntity</code>. '''AbstractWorldEntity'''`s one child class is '''AbstractPhysicalObject''', and AbstractWorldEntity is never instantiated in vanilla (so in practice everything in abstract world is an AbstractPhysicalObject). For more info on inheritance hierarchy, see [[../AbstractWorldEntity|this subpage]]. {| class="wikitable sortable" |+ AbstractWorldEntity useful members |- ! Member !! Kind !! Description |- | Abstractize || method || Called when entity should switch from realized to abstract state. Does nothing on this class (implementation is on AbstractPhysicalObject) |- | Destroy || method || Marks entity for deletion at the end{{Cn}} of the frame. |- | IsEnteringDen || method || Called when entering a creature den (not player shelter). |- | IsExitingDen || method || Called when exiting a creature den (not player shelter). |- | Update || method || Called every few frames. Argument <code>time</code> tells it how many frames have passed since last update. |- | Room || property || Returns abstract room this entity is in. |- | ID || field || Unique identifier of the entity. Used for generating properties of many things (for example, each time a creature with individual cosmetic variations, such as a Scavenger, is realized, it uses its ID as a seed to deterministically generate these stats) |- | InDen || field || Whether the entity is currently inside a creature den |- | pos || field || A <code>WorldCoordinate</code> of the creature. Stores room index and tile position of the entity. |- | slatedForDeletion || field || Whether entity should be deleted next abstract update |- | world || field || Reference to the World object entity belongs to |} {| class="wikitable sortable" |+ AbstractPhysicalObject useful members |- ! Member !! Kind !! Description |- | ChangeRooms || method || Moves instance from one room to another |- | GetAllConnectedObjects || method || Returns a list of all objects the instance is connected to |- | LoseAllStuckObjects || method || Unsticks all connected objects from itself |- | Move || method || Moves entity from one tile to another |- | Realize || method || Creates an appropriate realized object attached to this entity, without placing it in current room. Probably not for direct use{{Cn}} |- | RealizeInRoom || method || Creates an appropriate realized object attached to this entity, and adds it to current room |- | ToString || method || Returns a serialization string for this entity |- | destroyOnAbstraction || field || Whether this object should be destroyed when it exits realized space |- | realizedObject || field || Realized part of the entity. Null while in abstract LOD |- | stuckObjects || field || List of other objects that have been stuck to this one |- | tracker || field || An object carrying data the game uses for respawning key items, such as pearls or hunter's neuron. Null for most entities |- | type || field || An ExtEnum telling what kind of object this is (a spear, a neuron, a creature etc) |- || unrecognizedAttributes || field || '''An array of arbitrary strings attached to the instance. Contains data the game cannot parse. Saved appropriately, can be used by mods to attach data to AbstractPhysicalObjects''' |} == Realized layer == {{todo}} Rooms are <code>Room</code> (always attached to an instance of AbstractRoom), basic entities are <code>UpdatableAndDeletable</code>, AbstractPhysicalObject realized versions are <code>PhysicalObject</code>. Unlike with abstract LOD, '''UpdatableAndDeletable''' has children that are not '''PhysicalObject'''s (cosmetic sprites, background elements, etc). UpdatableAndDeletable may be shortened to UAD in this section. === UpdatableAndDeletable === Basic room entity. For inheritance hierarchy, see [[../UpdatableAndDeletable|this subpage]]. {| class="wikitable sortable" |+ UpdatableAndDeletable members |- ! Member !! Kind !! Description |- | Destroy || method || Marks UAD to be deleted at the end{{Cn}} of the frame |- | Update || method || Called every physics tick (40 TPS) when game is not paused |- | PausedUpdate || method || Called every physics tick when game is paused |- | RemoveFromRoom || method || Removes instance from room |- | slatedForDeletion || property || Indicates whether UAD will be deleted by the end{{Cn}} of the frame |- | room || field || Room this UAD belongs to |} <!-- todo: add interface descriptions? no wait that's in uad inheritance --> === PhysicalObject === All PhysicalObjects are composed of BodyChunks. Every BodyChunk has circular collision. Each PhysicalObject begins to a collision layer, of which there are 3 (0, 1 and 2). See [[../PhysicalObject_Basics|this]]. {| class="wikitable sortable" |+ PhysicalObject useful members |- ! Member !! Kind !! Description |- | ChangeCollisionLayer || method || Sets collision layer of instance |- | collisionLayer || field || Current collision layer. Invalid value will produce error on trying to add into room |- | Collide || method || Called every time instance touches another |- | TerrainImpact || method || Called every time instance hits terrain |- | Grabbed || method || Called every time instance is grabbed by a creature |- | HitByWeapon || method || Called every time instance is hit by a throwable weapon (such as a Spear). Applying damage to creatures is handled by the weapon itself, outside of this method |- | HitByExplosion || method || Called every time instance is hit by an explosion. Applying damage to creatures is handled by the explosion itself, outside of this method |- | graphicsModule || property || Helper object that manages the instance's visuals. Not all PhysicalObject children have graphics modules (for example, most creatures do, but weapons don't) |- | InitiateGraphicsModule || method || Called when room containing instance becomes visible. Intended behavior: filling graphicsModule field (without adding it to room). |- | GraphicsModuleUpdated || method || Called every time after the Room attempts to update its graphics module |- | DisposeGraphicsModule || method || Called when room containing instance becomes no longer visible. Detaches and destroys graphics module |- | NewRoom || method || Called when instance is added to a new room{{Cn}} |- | PlaceInRoom || method || Adds instance to a selected room |- | bodyChunks || property || An array of BodyChunk objects composing instance's body. Should always be instantiated by the constructor |- | appendages || field || A list of appendages this instance has. Appendages don't directly collide with body chunks, but still collide with terrain and can be hit by weapons{{Cn}}. Should always be instantiated by the constructor. Instances with appendages should implement <code>PhysicalObject.IHaveAppendages</code> |- | bodyChunkConnections || field || Array of objects determining how different chunks are physically tied to each other. Should always be instantiated by the constructor (empty if no chunk connections) |- | Gravity || property || Gravity of object. Calculated by multiplying room-wide gravity with instance's personal g value. Setter just sets g |- | g || field || Instance's personal gravity multiplier |- | airFriction || property || Air friction determines how much instance's velocity decays every frame. Applies when out of water or partially submerged. '''IMPORTANT''': Each frame chunk velocity is ''multiplied'' by friction value, so the expected value is in range between 0 and 1, usually very close to 1. If you set this to more than 1.0f, the object will accelerate exponentially! |- | waterFriction || property || Air friction determines how much instance's velocity decays every frame. Applies when out of water or partially submerged. '''IMPORTANT''': Each frame chunk velocity is ''multiplied'' by friction value, so the expected value is in range between 0 and 1, usually very close to 1. If you set this to more than 1.0f, the object will accelerate exponentially! |- | buoyancy || property || How much water pushes the object out. 0f means no pushout (instance stays suspended), negative values make instance sink, positive make it float to the surface. |- | GoThroughFloors || property || Whether instance should fall through platforms. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithObjects || property || Whether instance should collide with other objects on the same physics layer. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithTerrain || property || Whether instance should collide with solid terrain tiles. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithSlopes || property || Whether instance should collide with slope terrain tiles. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | submersion || property || Averaged submersion of all chunks |- | VisibilityBonus || property || Value used by AI on visual contact to roll for a creature spotting the instance. Positive values mean increased likelihood, negative means reduced likelihood |- | grabbedBy || field || List of things that are grabbing instance |} 103e3317f201b6dcff445b40fd898b142f38de89 475 473 2023-04-17T15:50:07Z Thalber 3 move abs table to its own page wikitext text/x-wiki {{todo|target=page}} Rain World uses two LOD ([https://en.wikipedia.org/wiki/Level_of_detail_(computer_graphics) Level Of Detail]) modes for entities in main loop: * Realized - high detail, updates every frame, physical interactions are fully rendered. Used in rooms close to player. * Abstract - low detail, each entity receives updates every several frames, physics interactions and detailed creature movements are replaced with simpler probabilistic interaction models (can be thought of as dice rolls). Default state. LOD level is selected on per-room basis, and is passed down on all entities in room. When in a realized room, abstract LOD entities (base class for these is (technically) AbstractWorldEntity and (practically) AbstractPhysicalObject) persist, but a realized version is attached to them until they abstractize again. All data not explicitly stored in abstract object is lost when an entity abstracts. This affects, for example, wolf spider revive mechanic: wolf spiders store a representation of one other spider they are willing to revive when they have body contact (<code>reviveBuddy</code> field in <code>BigSpiderAI</code>), and forget it when they leave realized space. == Abstract layer == Rooms are <code>AbstractRoom</code>, and all entities are <code>AbstractWorldEntity</code>. '''AbstractWorldEntity'''`s one child class is '''AbstractPhysicalObject''', and AbstractWorldEntity is never instantiated in vanilla (so in practice everything in abstract world is an AbstractPhysicalObject). For more info on inheritance hierarchy, see [[../AbstractWorldEntity|this subpage]]. == Realized layer == {{todo}} Rooms are <code>Room</code> (always attached to an instance of AbstractRoom), basic entities are <code>UpdatableAndDeletable</code>, AbstractPhysicalObject realized versions are <code>PhysicalObject</code>. Unlike with abstract LOD, '''UpdatableAndDeletable''' has children that are not '''PhysicalObject'''s (cosmetic sprites, background elements, etc). UpdatableAndDeletable may be shortened to UAD in this section. === UpdatableAndDeletable === Basic room entity. For inheritance hierarchy, see [[../UpdatableAndDeletable|this subpage]]. {| class="wikitable sortable" |+ UpdatableAndDeletable members |- ! Member !! Kind !! Description |- | Destroy || method || Marks UAD to be deleted at the end{{Cn}} of the frame |- | Update || method || Called every physics tick (40 TPS) when game is not paused |- | PausedUpdate || method || Called every physics tick when game is paused |- | RemoveFromRoom || method || Removes instance from room |- | slatedForDeletion || property || Indicates whether UAD will be deleted by the end{{Cn}} of the frame |- | room || field || Room this UAD belongs to |} <!-- todo: add interface descriptions? no wait that's in uad inheritance --> === PhysicalObject === All PhysicalObjects are composed of BodyChunks. Every BodyChunk has circular collision. Each PhysicalObject begins to a collision layer, of which there are 3 (0, 1 and 2). See [[../PhysicalObject_Basics|this]]. {| class="wikitable sortable" |+ PhysicalObject useful members |- ! Member !! Kind !! Description |- | ChangeCollisionLayer || method || Sets collision layer of instance |- | collisionLayer || field || Current collision layer. Invalid value will produce error on trying to add into room |- | Collide || method || Called every time instance touches another |- | TerrainImpact || method || Called every time instance hits terrain |- | Grabbed || method || Called every time instance is grabbed by a creature |- | HitByWeapon || method || Called every time instance is hit by a throwable weapon (such as a Spear). Applying damage to creatures is handled by the weapon itself, outside of this method |- | HitByExplosion || method || Called every time instance is hit by an explosion. Applying damage to creatures is handled by the explosion itself, outside of this method |- | graphicsModule || property || Helper object that manages the instance's visuals. Not all PhysicalObject children have graphics modules (for example, most creatures do, but weapons don't) |- | InitiateGraphicsModule || method || Called when room containing instance becomes visible. Intended behavior: filling graphicsModule field (without adding it to room). |- | GraphicsModuleUpdated || method || Called every time after the Room attempts to update its graphics module |- | DisposeGraphicsModule || method || Called when room containing instance becomes no longer visible. Detaches and destroys graphics module |- | NewRoom || method || Called when instance is added to a new room{{Cn}} |- | PlaceInRoom || method || Adds instance to a selected room |- | bodyChunks || property || An array of BodyChunk objects composing instance's body. Should always be instantiated by the constructor |- | appendages || field || A list of appendages this instance has. Appendages don't directly collide with body chunks, but still collide with terrain and can be hit by weapons{{Cn}}. Should always be instantiated by the constructor. Instances with appendages should implement <code>PhysicalObject.IHaveAppendages</code> |- | bodyChunkConnections || field || Array of objects determining how different chunks are physically tied to each other. Should always be instantiated by the constructor (empty if no chunk connections) |- | Gravity || property || Gravity of object. Calculated by multiplying room-wide gravity with instance's personal g value. Setter just sets g |- | g || field || Instance's personal gravity multiplier |- | airFriction || property || Air friction determines how much instance's velocity decays every frame. Applies when out of water or partially submerged. '''IMPORTANT''': Each frame chunk velocity is ''multiplied'' by friction value, so the expected value is in range between 0 and 1, usually very close to 1. If you set this to more than 1.0f, the object will accelerate exponentially! |- | waterFriction || property || Air friction determines how much instance's velocity decays every frame. Applies when out of water or partially submerged. '''IMPORTANT''': Each frame chunk velocity is ''multiplied'' by friction value, so the expected value is in range between 0 and 1, usually very close to 1. If you set this to more than 1.0f, the object will accelerate exponentially! |- | buoyancy || property || How much water pushes the object out. 0f means no pushout (instance stays suspended), negative values make instance sink, positive make it float to the surface. |- | GoThroughFloors || property || Whether instance should fall through platforms. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithObjects || property || Whether instance should collide with other objects on the same physics layer. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithTerrain || property || Whether instance should collide with solid terrain tiles. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithSlopes || property || Whether instance should collide with slope terrain tiles. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | submersion || property || Averaged submersion of all chunks |- | VisibilityBonus || property || Value used by AI on visual contact to roll for a creature spotting the instance. Positive values mean increased likelihood, negative means reduced likelihood |- | grabbedBy || field || List of things that are grabbing instance |} 1d0b79a4f40ab9e7d355b9293b8ffdb024df610a 479 475 2023-04-17T15:53:25Z Thalber 3 move uad table out wikitext text/x-wiki {{todo|target=page}} Rain World uses two LOD ([https://en.wikipedia.org/wiki/Level_of_detail_(computer_graphics) Level Of Detail]) modes for entities in main loop: * Realized - high detail, updates every frame, physical interactions are fully rendered. Used in rooms close to player. * Abstract - low detail, each entity receives updates every several frames, physics interactions and detailed creature movements are replaced with simpler probabilistic interaction models (can be thought of as dice rolls). Default state. LOD level is selected on per-room basis, and is passed down on all entities in room. When in a realized room, abstract LOD entities (base class for these is (technically) AbstractWorldEntity and (practically) AbstractPhysicalObject) persist, but a realized version is attached to them until they abstractize again. All data not explicitly stored in abstract object is lost when an entity abstracts. This affects, for example, wolf spider revive mechanic: wolf spiders store a representation of one other spider they are willing to revive when they have body contact (<code>reviveBuddy</code> field in <code>BigSpiderAI</code>), and forget it when they leave realized space. == Abstract layer == Rooms are <code>AbstractRoom</code>, and all entities are <code>AbstractWorldEntity</code>. '''AbstractWorldEntity'''`s one child class is '''AbstractPhysicalObject''', and AbstractWorldEntity is never instantiated in vanilla (so in practice everything in abstract world is an AbstractPhysicalObject). For more info on inheritance hierarchy, see [[../AbstractWorldEntity|this subpage]]. == Realized layer == {{todo}} Rooms are <code>Room</code> (always attached to an instance of AbstractRoom), basic entities are <code>UpdatableAndDeletable</code>, AbstractPhysicalObject realized versions are <code>PhysicalObject</code>. Unlike with abstract LOD, '''UpdatableAndDeletable''' has children that are not '''PhysicalObject'''s (cosmetic sprites, background elements, etc). UpdatableAndDeletable may be shortened to UAD in this section. === UpdatableAndDeletable === Basic room entity. For inheritance hierarchy, see [[../UpdatableAndDeletable|this subpage]]. <!-- todo: add interface descriptions? no wait that's in uad inheritance --> === PhysicalObject === All PhysicalObjects are composed of BodyChunks. Every BodyChunk has circular collision. Each PhysicalObject begins to a collision layer, of which there are 3 (0, 1 and 2). See [[../PhysicalObject_Basics|this]]. {| class="wikitable sortable" |+ PhysicalObject useful members |- ! Member !! Kind !! Description |- | ChangeCollisionLayer || method || Sets collision layer of instance |- | collisionLayer || field || Current collision layer. Invalid value will produce error on trying to add into room |- | Collide || method || Called every time instance touches another |- | TerrainImpact || method || Called every time instance hits terrain |- | Grabbed || method || Called every time instance is grabbed by a creature |- | HitByWeapon || method || Called every time instance is hit by a throwable weapon (such as a Spear). Applying damage to creatures is handled by the weapon itself, outside of this method |- | HitByExplosion || method || Called every time instance is hit by an explosion. Applying damage to creatures is handled by the explosion itself, outside of this method |- | graphicsModule || property || Helper object that manages the instance's visuals. Not all PhysicalObject children have graphics modules (for example, most creatures do, but weapons don't) |- | InitiateGraphicsModule || method || Called when room containing instance becomes visible. Intended behavior: filling graphicsModule field (without adding it to room). |- | GraphicsModuleUpdated || method || Called every time after the Room attempts to update its graphics module |- | DisposeGraphicsModule || method || Called when room containing instance becomes no longer visible. Detaches and destroys graphics module |- | NewRoom || method || Called when instance is added to a new room{{Cn}} |- | PlaceInRoom || method || Adds instance to a selected room |- | bodyChunks || property || An array of BodyChunk objects composing instance's body. Should always be instantiated by the constructor |- | appendages || field || A list of appendages this instance has. Appendages don't directly collide with body chunks, but still collide with terrain and can be hit by weapons{{Cn}}. Should always be instantiated by the constructor. Instances with appendages should implement <code>PhysicalObject.IHaveAppendages</code> |- | bodyChunkConnections || field || Array of objects determining how different chunks are physically tied to each other. Should always be instantiated by the constructor (empty if no chunk connections) |- | Gravity || property || Gravity of object. Calculated by multiplying room-wide gravity with instance's personal g value. Setter just sets g |- | g || field || Instance's personal gravity multiplier |- | airFriction || property || Air friction determines how much instance's velocity decays every frame. Applies when out of water or partially submerged. '''IMPORTANT''': Each frame chunk velocity is ''multiplied'' by friction value, so the expected value is in range between 0 and 1, usually very close to 1. If you set this to more than 1.0f, the object will accelerate exponentially! |- | waterFriction || property || Air friction determines how much instance's velocity decays every frame. Applies when out of water or partially submerged. '''IMPORTANT''': Each frame chunk velocity is ''multiplied'' by friction value, so the expected value is in range between 0 and 1, usually very close to 1. If you set this to more than 1.0f, the object will accelerate exponentially! |- | buoyancy || property || How much water pushes the object out. 0f means no pushout (instance stays suspended), negative values make instance sink, positive make it float to the surface. |- | GoThroughFloors || property || Whether instance should fall through platforms. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithObjects || property || Whether instance should collide with other objects on the same physics layer. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithTerrain || property || Whether instance should collide with solid terrain tiles. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithSlopes || property || Whether instance should collide with slope terrain tiles. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | submersion || property || Averaged submersion of all chunks |- | VisibilityBonus || property || Value used by AI on visual contact to roll for a creature spotting the instance. Positive values mean increased likelihood, negative means reduced likelihood |- | grabbedBy || field || List of things that are grabbing instance |} 0df9b3f041caf256198f02bb1c1e5c5302489640 481 479 2023-04-17T15:57:50Z Thalber 3 move physobj table out wikitext text/x-wiki {{todo|target=page}} Rain World uses two LOD ([https://en.wikipedia.org/wiki/Level_of_detail_(computer_graphics) Level Of Detail]) modes for entities in main loop: * Realized - high detail, updates every frame, physical interactions are fully rendered. Used in rooms close to player. * Abstract - low detail, each entity receives updates every several frames, physics interactions and detailed creature movements are replaced with simpler probabilistic interaction models (can be thought of as dice rolls). Default state. LOD level is selected on per-room basis, and is passed down on all entities in room. When in a realized room, abstract LOD entities (base class for these is (technically) AbstractWorldEntity and (practically) AbstractPhysicalObject) persist, but a realized version is attached to them until they abstractize again. All data not explicitly stored in abstract object is lost when an entity abstracts. This affects, for example, wolf spider revive mechanic: wolf spiders store a representation of one other spider they are willing to revive when they have body contact (<code>reviveBuddy</code> field in <code>BigSpiderAI</code>), and forget it when they leave realized space. == Abstract layer == Rooms are <code>AbstractRoom</code>, and all entities are <code>AbstractWorldEntity</code>. '''AbstractWorldEntity'''`s one child class is '''AbstractPhysicalObject''', and AbstractWorldEntity is never instantiated in vanilla (so in practice everything in abstract world is an AbstractPhysicalObject). For more info on inheritance hierarchy, see [[../AbstractWorldEntity|this subpage]]. == Realized layer == {{todo}} Rooms are <code>Room</code> (always attached to an instance of AbstractRoom), basic entities are <code>UpdatableAndDeletable</code>, AbstractPhysicalObject realized versions are <code>PhysicalObject</code>. Unlike with abstract LOD, '''UpdatableAndDeletable''' has children that are not '''PhysicalObject'''s (cosmetic sprites, background elements, etc). UpdatableAndDeletable may be shortened to UAD in this section. === UpdatableAndDeletable === Basic room entity. For inheritance hierarchy, see [[../UpdatableAndDeletable|this subpage]]. <!-- todo: add interface descriptions? no wait that's in uad inheritance --> === PhysicalObject === All PhysicalObjects are composed of BodyChunks. Every BodyChunk has circular collision. Each PhysicalObject begins to a collision layer, of which there are 3 (0, 1 and 2). See [[../PhysicalObject_Basics|this]]. d4f4a20f64cdbb52d88c225a8a441af3b300684e 482 481 2023-04-17T16:03:45Z Thalber 3 wikitext text/x-wiki {{todo|target=page}} Rain World uses two LOD ([https://en.wikipedia.org/wiki/Level_of_detail_(computer_graphics) Level Of Detail]) modes for entities in main loop: * Realized - high detail, updates every frame, physical interactions are fully rendered. Used in rooms close to player. * Abstract - low detail, each entity receives updates every several frames, physics interactions and detailed creature movements are replaced with simpler probabilistic interaction models (can be thought of as dice rolls). Default state. LOD level is selected on per-room basis, and is passed down on all entities in room. When in a realized room, abstract LOD entities (base class for these is (technically) AbstractWorldEntity and (practically) AbstractPhysicalObject) persist, but a realized version is attached to them until they abstractize again. All data not explicitly stored in abstract object is lost when an entity abstracts. This affects, for example, wolf spider revive mechanic: wolf spiders store a representation of one other spider they are willing to revive when they have body contact (<code>reviveBuddy</code> field in <code>BigSpiderAI</code>), and forget it when they leave realized space. == Abstract layer == Rooms are <code>AbstractRoom</code>, and all entities are <code>AbstractWorldEntity</code>. '''AbstractWorldEntity'''`s one child class is '''AbstractPhysicalObject''', and AbstractWorldEntity is never instantiated in vanilla (so in practice everything in abstract world is an AbstractPhysicalObject). For more info on inheritance hierarchy, see [[../AbstractWorldEntity|this subpage]]. == Realized layer == Rooms are <code>Room</code> (always attached to an instance of AbstractRoom), basic entities are <code>UpdatableAndDeletable</code>, AbstractPhysicalObject realized versions are <code>PhysicalObject</code>. Unlike with abstract LOD, '''UpdatableAndDeletable''' has children that are not '''PhysicalObject'''s (cosmetic sprites, background elements, etc). UpdatableAndDeletable may be shortened to UAD in this section. === UpdatableAndDeletable === The most basic room entity. As the name suggests, can be added to a room, updated inside a room and deleted from a room. See [[../UpdatableAndDeletable|this subpage]] for details. === PhysicalObject === Realized LOD versions of '''AbstractPhysicalObject'''s. Everything that can be whacked and tossed. See [[../PhysicalObject_Basics|this subpage]] for details. 981bc0264f978164541c3115828ab7ce37deaf26 Template:BadgeBase 10 183 470 423 2023-04-17T15:13:47Z Thalber 3 small fix wikitext text/x-wiki <includeonly><div class="nomobile">{{Ambox | image = <p><span style="margin-right:15px>[[File:{{{icon|sloogo.png}}}|47px|middle]]</span> | type = '''{{{title|Badge title here}}}''' | info = {{{body|Badge body here.}}}</p> | border = {{{color|gray}}} }}</div></includeonly><noinclude> <nowiki> {{BadgeBase}} {{BadgeBase|title=You can change title of the badge|body=And its body text too}} {{BadgeBase|color=red|title=A very red badge|body=Hunter body here|icon=hunterAngy.png}} </nowiki> {{BadgeBase}} {{BadgeBase|title=You can change title of the badge|body=And its body text too}} {{BadgeBase|color=red|title=A very red badge|body=Hunter body here|icon=hunterAngy.png}} </noinclude> 6a920b9a12399ff5b88070d12faf883240e0426a Rain World Code Structure 0 187 472 440 2023-04-17T15:46:16Z Thalber 3 wikitext text/x-wiki {{todo|target=article}} This article describes how Rain World vanilla code is laid out, and relationships between different parts. {| class="wikitable" |+ Subsections |- ! Subsection !! Description |- | [[/RainWorld]] || Singleton holding the game |- | [[/Options]] || Class containing user settings |- | [[/ProcessManager_and_Subprocesses]] || Different modes the game can operate in |- | [[/GameSession]] || Different gamemodes (arena/story/safari) |- | [[/Save_Data]] || Different types of save data and rules of its saving/erasing |- | [[/LOD]] || Two Level Of Detail modes game entities inside a GameSession can exist in |- | [[/World]] || Holds your journey together |- | [[/Rooms]] || Building blocks of a world |- | [[/AbstractWorldEntity]] || Abstract [[/LOD]] entities |- <!--| [[/AbstractCreature]] || Creatures existing in abstract [[/LOD]]. |---> | [[/Abstract_AI]] || AI for abstract layer creatures (see [[/AbstractWorldEntity_Inheritance]]) |- | [[/CreatureState]] || Different states of creatures |- | [[/UpdatableAndDeletable]] || The most basic realize world item and what kinds of children it can have |- | [[/PhysicalObject]] || Class for things that have collision. Dependent on AbstractPhysicalObject ([[/AbstractWorldEntity]]) |- <!--|- | [[/PhysicalObject_Inheritance]] || Classification of physical items. --> <!--| [[/Creature]] || Creatures existing in realized [[/LOD]] ([[/PhysicalObject_Inheritance]]). |---> | [[/Realized_AI]] || AI for realized level creatures (base class: ArtificialIntelligence) (see [[/PhysicalObject]]) |- | [[/GraphicsModule]] || Some [[/PhysicalObject]]s separate their graphics into a separate class that is only brought into existence when they are on screen |- | [[/ComplexGraphicsModule]] || Graphics modules for creatures with exceptionally convoluted draw logic are modular |- | [[/RoomCamera]] || Single in vanilla, not so much with mods |- | [[/Physics]] || Where, when and how collisions are calculated |- | [[/Sound_System]] || SFX and music |- | [[/MSC_Namespace_and_Conditional_Enums]] || When and where code exclusive to the DLC is included or excluded |} f98ee997bd84e9166ba902ad0543904d54370990 487 472 2023-04-17T18:42:25Z Thalber 3 wikitext text/x-wiki {{todo|target=article}} This article describes how Rain World vanilla code is laid out, and relationships between different parts. {| class="wikitable" |+ Subsections |- ! Subsection !! Description |- | [[/RainWorld]] || Singleton holding the game |- | [[/Options]] || Class containing user settings |- | [[/ProcessManager_and_Subprocesses]] || Different modes the game can operate in |- | [[/GameSession]] || Different gamemodes (arena/story/safari) |- | [[/Save_Data]] || Different types of save data and rules of its saving/erasing |- | [[/LOD]] || Two Level Of Detail modes game entities inside a GameSession can exist in |- | [[/World]] || Holds your journey together |- | [[/Rooms]] || Building blocks of a world |- | [[/AbstractWorldEntity]] || Abstract [[/LOD]] entities |- <!--| [[/AbstractCreature]] || Creatures existing in abstract [[/LOD]]. |---> | [[/Abstract_AI]] || AI for abstract layer creatures (see [[/AbstractWorldEntity]]) |- | [[/CreatureState]] || Different states of creatures |- | [[/UpdatableAndDeletable]] || The most basic realize world item and what kinds of children it can have |- | [[/PhysicalObject]] || Class for things that have collision. Dependent on AbstractPhysicalObject ([[/AbstractWorldEntity]]) |- <!--|- | [[/PhysicalObject_Inheritance]] || Classification of physical items. --> <!--| [[/Creature]] || Creatures existing in realized [[/LOD]] ([[/PhysicalObject_Inheritance]]). |---> | [[/Realized_AI]] || AI for realized level creatures (base class: ArtificialIntelligence) (see [[/PhysicalObject]]) |- | [[/GraphicsModule]] || Some [[/PhysicalObject]]s separate their graphics into a separate class that is only brought into existence when they are on screen |- | [[/ComplexGraphicsModule]] || Graphics modules for creatures with exceptionally convoluted draw logic are modular |- | [[/RoomCamera]] || Single in vanilla, not so much with mods |- | [[/Physics]] || Where, when and how collisions are calculated |- | [[/Sound_System]] || SFX and music |- | [[/MSC_Namespace_and_Conditional_Enums]] || When and where code exclusive to the DLC is included or excluded |} 074506881519bbcdf2f27935f1adaa0d7697f452 489 487 2023-04-18T13:50:38Z Thalber 3 wikitext text/x-wiki {{todo|target=article}} This article describes how Rain World vanilla code is laid out, and relationships between different parts. {| class="wikitable" |+ Subsections |- ! Subsection !! Description |- | [[/RainWorld]] || Singleton holding the game |- | [[/Options]] || Class containing user settings |- | [[/ProcessManager_and_Subprocesses]] || Different modes the game can operate in |- | [[/GameSession]] || Different gamemodes (arena/story/safari) |- | [[/Save_Data]] || Different types of save data and rules of its saving/erasing |- | [[/LOD]] || Two Level Of Detail modes game entities inside a GameSession can exist in |- | [[/World]] || Holds your journey together |- | [[/Rooms]] || Building blocks of a world |- | [[/AbstractWorldEntity]] || Abstract [[/LOD]] entities |- | [[AbstractCreature]] || Abstract LOD creatures |- | [[/AbstractCreatureAI]] || AI for abstract layer creatures (see [[/AbstractWorldEntity]]) |- | [[/CreatureState]] || Different states of creatures |- | [[/UpdatableAndDeletable]] || The most basic realize world item and what kinds of children it can have |- | [[/PhysicalObject]] || Class for things that have collision. Dependent on AbstractPhysicalObject ([[/AbstractWorldEntity]]) |- | [[/Creature]] || Base class for realized LOD creatures |- | [[/ArtificialIntelligence]] || AI for realized level creatures (base class: ArtificialIntelligence) (see [[/PhysicalObject]]) |- | [[/GraphicsModule]] || Some [[/PhysicalObject]]s separate their graphics into a separate class that is only brought into existence when they are on screen |- | [[/ComplexGraphicsModule]] || Graphics modules for creatures with exceptionally convoluted draw logic are modular |- | [[/RoomCamera]] || Single in vanilla, not so much with mods |- | [[/Physics]] || Where, when and how collisions are calculated |- | [[/Sound_System]] || SFX and music |- | [[/MSC_Namespace_and_Conditional_Enums]] || When and where code exclusive to the DLC is included or excluded |} 310eb3d19515da1409ab70a067be06a29d2399da 490 489 2023-04-18T13:53:24Z Thalber 3 wikitext text/x-wiki {{todo|target=article}} This article describes how Rain World vanilla code is laid out, and relationships between different parts. {| class="wikitable" |+ Subsections |- ! Subsection !! Description |- | [[/RainWorld]] || Singleton holding the game |- | [[/Options]] || Class containing user settings |- | [[/ProcessManager_and_Subprocesses]] || Different modes the game can operate in |- | [[/GameSession]] || Different gamemodes (arena/story/safari) |- | [[/Save_Data]] || Different types of save data and rules of its saving/erasing |- | [[/LOD]] || Two Level Of Detail modes game entities inside a GameSession can exist in |- | [[/World]] || Holds your journey together |- | [[/Rooms]] || Building blocks of a world |- | [[/AbstractWorldEntity]] || Abstract [[/LOD]] entities |- | [[/AbstractCreature]] || Abstract LOD creatures |- | [[/AbstractCreatureAI]] || AI for abstract layer creatures (see [[/AbstractWorldEntity]]) |- | [[/CreatureState]] || Different states of creatures |- | [[/UpdatableAndDeletable]] || The most basic realize world item and what kinds of children it can have |- | [[/PhysicalObject]] || Class for things that have collision. Dependent on AbstractPhysicalObject ([[/AbstractWorldEntity]]) |- | [[/Creature]] || Base class for realized LOD creatures |- | [[/ArtificialIntelligence]] || AI for realized level creatures (base class: ArtificialIntelligence) (see [[/PhysicalObject]]) |- | [[/GraphicsModule]] || Some [[/PhysicalObject]]s separate their graphics into a separate class that is only brought into existence when they are on screen |- | [[/ComplexGraphicsModule]] || Graphics modules for creatures with exceptionally convoluted draw logic are modular |- | [[/RoomCamera]] || Single in vanilla, not so much with mods |- | [[/Physics]] || Where, when and how collisions are calculated |- | [[/Sound_System]] || SFX and music |- | [[/MSC_Namespace_and_Conditional_Enums]] || When and where code exclusive to the DLC is included or excluded |} 0dcf9ef0573988f8ac13072bbac28c5f2139ff15 Rain World Code Structure/AbstractWorldEntity 0 193 474 2023-04-17T15:49:50Z Thalber 3 init wikitext text/x-wiki {{Cleanup}} Base class for all abstract [[../LOD|LOD]] entities. '''AbstractWorldEntity'''`s one child class is '''AbstractPhysicalObject''', and AbstractWorldEntity is never instantiated in vanilla (so in practice everything in abstract world is an AbstractPhysicalObject). {| class="wikitable sortable" |+ AbstractWorldEntity useful members |- ! Member !! Kind !! Description |- | Abstractize || method || Called when entity should switch from realized to abstract state. Does nothing on this class (implementation is on AbstractPhysicalObject) |- | Destroy || method || Marks entity for deletion at the end{{Cn}} of the frame. |- | IsEnteringDen || method || Called when entering a creature den (not player shelter). |- | IsExitingDen || method || Called when exiting a creature den (not player shelter). |- | Update || method || Called every few frames. Argument <code>time</code> tells it how many frames have passed since last update. |- | Room || property || Returns abstract room this entity is in. |- | ID || field || Unique identifier of the entity. Used for generating properties of many things (for example, each time a creature with individual cosmetic variations, such as a Scavenger, is realized, it uses its ID as a seed to deterministically generate these stats) |- | InDen || field || Whether the entity is currently inside a creature den |- | pos || field || A <code>WorldCoordinate</code> of the creature. Stores room index and tile position of the entity. |- | slatedForDeletion || field || Whether entity should be deleted next abstract update |- | world || field || Reference to the World object entity belongs to |} {| class="wikitable sortable" |+ AbstractPhysicalObject useful members |- ! Member !! Kind !! Description |- | ChangeRooms || method || Moves instance from one room to another |- | GetAllConnectedObjects || method || Returns a list of all objects the instance is connected to |- | LoseAllStuckObjects || method || Unsticks all connected objects from itself |- | Move || method || Moves entity from one tile to another |- | Realize || method || Creates an appropriate realized object attached to this entity, without placing it in current room. Probably not for direct use{{Cn}} |- | RealizeInRoom || method || Creates an appropriate realized object attached to this entity, and adds it to current room |- | ToString || method || Returns a serialization string for this entity |- | destroyOnAbstraction || field || Whether this object should be destroyed when it exits realized space |- | realizedObject || field || Realized part of the entity. Null while in abstract LOD |- | stuckObjects || field || List of other objects that have been stuck to this one |- | tracker || field || An object carrying data the game uses for respawning key items, such as pearls or hunter's neuron. Null for most entities |- | type || field || An ExtEnum telling what kind of object this is (a spear, a neuron, a creature etc) |- || unrecognizedAttributes || field || '''An array of arbitrary strings attached to the instance. Contains data the game cannot parse. Saved appropriately, can be used by mods to attach data to AbstractPhysicalObjects''' |} 50f6ea35061e8180fe943324f9d85e7a7ea93f3f 477 474 2023-04-17T15:53:01Z Thalber 3 wikitext text/x-wiki {{Cleanup}} Base class for all abstract [[../LOD|LOD]] entities. '''AbstractWorldEntity'''`s one child class is '''AbstractPhysicalObject''', and AbstractWorldEntity is never instantiated in vanilla (so in practice everything in abstract world is an AbstractPhysicalObject). {| class="wikitable sortable" |+ AbstractWorldEntity useful members |- ! Member !! Kind !! Description |- | Abstractize || method || Called when entity should switch from realized to abstract state. Does nothing on this class (implementation is on AbstractPhysicalObject) |- | Destroy || method || Marks entity for deletion at the end{{Cn}} of the frame. |- | IsEnteringDen || method || Called when entering a creature den (not player shelter). |- | IsExitingDen || method || Called when exiting a creature den (not player shelter). |- | Update || method || Called every few frames. Argument <code>time</code> tells it how many frames have passed since last update. |- | Room || property || Returns abstract room this entity is in. |- | ID || field || Unique identifier of the entity. Used for generating properties of many things (for example, each time a creature with individual cosmetic variations, such as a Scavenger, is realized, it uses its ID as a seed to deterministically generate these stats) |- | InDen || field || Whether the entity is currently inside a creature den |- | pos || field || A <code>WorldCoordinate</code> of the creature. Stores room index and tile position of the entity. |- | slatedForDeletion || field || Whether entity should be deleted next abstract update |- | world || field || Reference to the World object entity belongs to |} {| class="wikitable sortable" |+ AbstractPhysicalObject useful members |- ! Member !! Kind !! Description |- | ChangeRooms || method || Moves instance from one room to another |- | GetAllConnectedObjects || method || Returns a list of all objects the instance is connected to |- | LoseAllStuckObjects || method || Unsticks all connected objects from itself |- | Move || method || Moves entity from one tile to another |- | Realize || method || Creates an appropriate realized object attached to this entity, without placing it in current room. Probably not for direct use{{Cn}} |- | RealizeInRoom || method || Creates an appropriate realized object attached to this entity, and adds it to current room |- | ToString || method || Returns a serialization string for this entity |- | destroyOnAbstraction || field || Whether this object should be destroyed when it exits realized space |- | realizedObject || field || Realized part of the entity. Null while in abstract LOD |- | stuckObjects || field || List of other objects that have been stuck to this one |- | tracker || field || An object carrying data the game uses for respawning key items, such as pearls or hunter's neuron. Null for most entities |- | type || field || An ExtEnum telling what kind of object this is (a spear, a neuron, a creature etc) |- || unrecognizedAttributes || field || '''An array of arbitrary strings attached to the instance. Contains data the game cannot parse. Saved appropriately, can be used by mods to attach data to AbstractPhysicalObjects''' |} == Child classes == {{todo}} == Interfaces == {{todo}} 077af133678dcb3f6c56722a2b84a388a25d27a0 494 477 2023-04-18T14:19:56Z Thalber 3 wikitext text/x-wiki {{Cleanup}} Base class for all abstract [[../LOD|LOD]] entities. '''AbstractWorldEntity'''`s one child class is '''AbstractPhysicalObject''', and AbstractWorldEntity is never instantiated in vanilla (so in practice everything in abstract world is an AbstractPhysicalObject). {| class="wikitable sortable" |+ AbstractWorldEntity useful members |- ! Member !! Kind !! Description |- | Abstractize || method || Called when entity should switch from realized to abstract state. Does nothing on this class (implementation is on AbstractPhysicalObject) |- | Destroy || method || Marks entity for deletion at the end{{Cn}} of the frame. |- | IsEnteringDen || method || Called when entering a creature den (not player shelter). |- | IsExitingDen || method || Called when exiting a creature den (not player shelter). |- | Update || method || Called every few frames. Argument <code>time</code> tells it how many frames have passed since last update. |- | Room || property || Returns abstract room this entity is in. |- | ID || field || Unique identifier of the entity. Used for generating properties of many things (for example, each time a creature with individual cosmetic variations, such as a Scavenger, is realized, it uses its ID as a seed to deterministically generate these stats) |- | InDen || field || Whether the entity is currently inside a creature den |- | pos || field || A <code>WorldCoordinate</code> of the creature. Stores room index and tile position of the entity. |- | slatedForDeletion || field || Whether entity should be deleted next abstract update |- | world || field || Reference to the World object entity belongs to |} {| class="wikitable sortable" |+ AbstractPhysicalObject useful members |- ! Member !! Kind !! Description |- | ChangeRooms || method || Moves instance from one room to another |- | GetAllConnectedObjects || method || Returns a list of all objects the instance is connected to |- | LoseAllStuckObjects || method || Unsticks all connected objects from itself |- | Move || method || Moves entity from one tile to another |- | Realize || method || Creates an appropriate realized object attached to this entity, without placing it in current room. Probably not for direct use{{Cn}} |- | RealizeInRoom || method || Creates an appropriate realized object attached to this entity, and adds it to current room |- | ToString || method || Returns a serialization string for this entity |- | destroyOnAbstraction || field || Whether this object should be destroyed when it exits realized space |- | realizedObject || field || Realized part of the entity. Null while in abstract LOD |- | stuckObjects || field || List of other objects that have been stuck to this one |- | tracker || field || An object carrying data the game uses for respawning key items, such as pearls or hunter's neuron. Null for most entities |- | type || field || An ExtEnum telling what kind of object this is (a spear, a neuron, a creature etc) |- || unrecognizedAttributes || field || '''An array of arbitrary strings attached to the instance. Contains data the game cannot parse. Saved appropriately, can be used by mods to attach data to AbstractPhysicalObjects''' |} == Child classes == Notable subcategories of AbstractPhysicalObject: * '''AbstractConsumable''' - things that respawn on a timer. These are abstract representations for consumables placed in devtools, such as waternuts and flashbangs. * '''[[../AbstractCreature|AbstractCreature]]''' - all abstract LOD creatures == Interfaces == AWE/APO do not have any interfaces. aa11bfd7b67b715273c6eef7f9e95a7614c71b4c Rain World Code Structure/UpdatableAndDeletable 0 194 476 2023-04-17T15:52:28Z Thalber 3 init wikitext text/x-wiki '''UpdatableAndDeletable''' is the most basic Realized [[../LOD|LOD]] entity. {| class="wikitable sortable" |+ UpdatableAndDeletable members |- ! Member !! Kind !! Description |- | Destroy || method || Marks UAD to be deleted at the end{{Cn}} of the frame |- | Update || method || Called every physics tick (40 TPS) when game is not paused |- | PausedUpdate || method || Called every physics tick when game is paused |- | RemoveFromRoom || method || Removes instance from room |- | slatedForDeletion || property || Indicates whether UAD will be deleted by the end{{Cn}} of the frame |- | room || field || Room this UAD belongs to |} == Child class tree == {{todo}} == Interfaces == {{todo}} 485e2f663bd5abd06fcada8bfa99dd3d0140dc8b 478 476 2023-04-17T15:53:12Z Thalber 3 wikitext text/x-wiki '''UpdatableAndDeletable''' is the most basic Realized [[../LOD|LOD]] entity. {| class="wikitable sortable" |+ UpdatableAndDeletable members |- ! Member !! Kind !! Description |- | Destroy || method || Marks UAD to be deleted at the end{{Cn}} of the frame |- | Update || method || Called every physics tick (40 TPS) when game is not paused |- | PausedUpdate || method || Called every physics tick when game is paused |- | RemoveFromRoom || method || Removes instance from room |- | slatedForDeletion || property || Indicates whether UAD will be deleted by the end{{Cn}} of the frame |- | room || field || Room this UAD belongs to |} == Child classes == {{todo}} == Interfaces == {{todo}} 853692d7997dd347c46f470e82c38f9418e785c6 484 478 2023-04-17T18:12:21Z Thalber 3 wikitext text/x-wiki '''UpdatableAndDeletable''' is the most basic Realized [[../LOD|LOD]] entity. {| class="wikitable sortable" |+ UpdatableAndDeletable members |- ! Member !! Kind !! Description |- | Destroy || method || Marks UAD to be deleted at the end{{Cn}} of the frame |- | Update || method || Called every physics tick (40 TPS) when game is not paused |- | PausedUpdate || method || Called every physics tick when game is paused |- | RemoveFromRoom || method || Removes instance from room |- | slatedForDeletion || property || Indicates whether UAD will be deleted by the end{{Cn}} of the frame |- | room || field || Room this UAD belongs to |} == Child classes == {{todo}} == Interfaces == {{todo}} <!-- Phys PhysicalObject.IHaveAppendages ILookingAtCreatures IPlayerEdible ITeleportingCreature--> These are interfaces that every UAD can implement: {| class="wikitable" |- ! Interface !! Description |- | Weapon.INotifyOfFlyingWeapons || Receives calls when there are weapons thrown in the room |- | SharedPhysics.IProjectileTracer || {{todo|target=cell}} |- | IAccessibilityModifier || Modifies pathfinding accessibility |- | ISingleCameraDrawable || An object with visuals that can only be drawn on one camera. Only implemented by ScoreLabel and would require hooks to use for a modded class |- | IDrawable || Something with visuals |- | IClimbableVine || Objects representing player-climbable ropes, such as corruption tubes. Vines are not climbable by creatures |- | INotifyWhenRoomIsReady || Receives notifications when room loading breakpoints are reached - when the room has calculated shortcut data and when the room has finished deserializing/calculating AI navmap |- | IOwnMycelia || Objects that own neural mycelia{{Cn|anything else?}} |- | IOwnProjectedCircles || Objects that own iterator holo circles (they show up when a room has AI projection objects in it){{Cn|better way to describe?}} |} For interfaces that are only applicable for PhysicalObjects, see [[../PhysicalObject|this subpage]]. 8f1b22cd5984c4cfca62315140441c03a404a832 485 484 2023-04-17T18:12:41Z Thalber 3 wikitext text/x-wiki '''UpdatableAndDeletable''' is the most basic Realized [[../LOD|LOD]] entity. {| class="wikitable sortable" |+ UpdatableAndDeletable members |- ! Member !! Kind !! Description |- | Destroy || method || Marks UAD to be deleted at the end{{Cn}} of the frame |- | Update || method || Called every physics tick (40 TPS) when game is not paused |- | PausedUpdate || method || Called every physics tick when game is paused |- | RemoveFromRoom || method || Removes instance from room |- | slatedForDeletion || property || Indicates whether UAD will be deleted by the end{{Cn}} of the frame |- | room || field || Room this UAD belongs to |} == Child classes == {{todo}} == Interfaces == <!-- Phys PhysicalObject.IHaveAppendages ILookingAtCreatures IPlayerEdible ITeleportingCreature--> These are interfaces that every UAD can implement: {| class="wikitable" |- ! Interface !! Description |- | Weapon.INotifyOfFlyingWeapons || Receives calls when there are weapons thrown in the room |- | SharedPhysics.IProjectileTracer || {{todo|target=cell}} |- | IAccessibilityModifier || Modifies pathfinding accessibility |- | ISingleCameraDrawable || An object with visuals that can only be drawn on one camera. Only implemented by ScoreLabel and would require hooks to use for a modded class |- | IDrawable || Something with visuals |- | IClimbableVine || Objects representing player-climbable ropes, such as corruption tubes. Vines are not climbable by creatures |- | INotifyWhenRoomIsReady || Receives notifications when room loading breakpoints are reached - when the room has calculated shortcut data and when the room has finished deserializing/calculating AI navmap |- | IOwnMycelia || Objects that own neural mycelia{{Cn|anything else?}} |- | IOwnProjectedCircles || Objects that own iterator holo circles (they show up when a room has AI projection objects in it){{Cn|better way to describe?}} |} For interfaces that are only applicable for PhysicalObjects, see [[../PhysicalObject|this subpage]]. d2a08ebbf988a1e6cbea0d82307cee22c76a7402 486 485 2023-04-17T18:41:30Z Thalber 3 wikitext text/x-wiki '''UpdatableAndDeletable''' is the most basic Realized [[../LOD|LOD]] entity. {| class="wikitable sortable" |+ UpdatableAndDeletable members |- ! Member !! Kind !! Description |- | Destroy || method || Marks UAD to be deleted at the end{{Cn}} of the frame |- | Update || method || Called every physics tick (40 TPS) when game is not paused |- | PausedUpdate || method || Called every physics tick when game is paused |- | RemoveFromRoom || method || Removes instance from room |- | slatedForDeletion || property || Indicates whether UAD will be deleted by the end{{Cn}} of the frame |- | room || field || Room this UAD belongs to |} == Child classes == {{todo}} This section lists notable subcategories of UpdatableAndDeletable. {| class="wikitable" |- ! Subset !! Description |- | BackgroundScene || A complex background graphic with parallax scrolling. It is not an IDrawable itself, delegating sprite handling to BackgroundSceneElements. |- | BackgroundSceneElement || IDrawable. Building blocks of a bgscene. Each one represents a singular background piece, such as an iterator can, comms spire or a cloud layer. |- | CosmeticSprite || IDrawable. Particles and sprites that generally do not impact gameplay (with the exception of <code>SporeCloud</code>, which applies poison to insectoid creatures close to it). A sizeable subset of these are <code>CosmeticInsect</code>s. |- | OverseerHologram || Holograms projected by Iggy and other overseers. Cannot be used without an overseer. Instantiation code is a mess. |- | Smoke.SmokeSystem || A smoke emitter. Supports wind sway from passing creatures and explosions. |- | PhysicalObject || Too much to describe here. Gets its own [[../PhysicalObject|page]]. |} == Interfaces == <!-- Phys PhysicalObject.IHaveAppendages ILookingAtCreatures IPlayerEdible ITeleportingCreature--> These are interfaces that every UAD can implement: {| class="wikitable" |- ! Interface !! Description |- | Weapon.INotifyOfFlyingWeapons || Receives calls when there are weapons thrown in the room |- | SharedPhysics.IProjectileTracer || {{todo|target=cell}} |- | IAccessibilityModifier || Modifies pathfinding accessibility |- | ISingleCameraDrawable || An object with visuals that can only be drawn on one camera. Only implemented by ScoreLabel and would require hooks to use for a modded class |- | IDrawable || Something with visuals |- | IClimbableVine || Objects representing player-climbable ropes, such as corruption tubes. Vines are not climbable by creatures |- | INotifyWhenRoomIsReady || Receives notifications when room loading breakpoints are reached - when the room has calculated shortcut data and when the room has finished deserializing/calculating AI navmap |- | IOwnMycelia || Objects that own neural mycelia stalks{{Cn|anything else?}} |- | IOwnProjectedCircles || Objects that own iterator holo circles (they show up when a room has AI projection objects in it){{Cn|better way to describe?}} |} For interfaces that are only applicable for PhysicalObjects, see [[../PhysicalObject|this subpage]]. 1e3643e276953d7be786b817fdeb57f43c36893f 493 486 2023-04-18T14:03:37Z Thalber 3 /* Child classes */ wikitext text/x-wiki '''UpdatableAndDeletable''' is the most basic Realized [[../LOD|LOD]] entity. {| class="wikitable sortable" |+ UpdatableAndDeletable members |- ! Member !! Kind !! Description |- | Destroy || method || Marks UAD to be deleted at the end{{Cn}} of the frame |- | Update || method || Called every physics tick (40 TPS) when game is not paused |- | PausedUpdate || method || Called every physics tick when game is paused |- | RemoveFromRoom || method || Removes instance from room |- | slatedForDeletion || property || Indicates whether UAD will be deleted by the end{{Cn}} of the frame |- | room || field || Room this UAD belongs to |} == Child classes == This section lists notable subcategories of UpdatableAndDeletable. {| class="wikitable" |- ! Subset !! Description |- | BackgroundScene || A complex background graphic with parallax scrolling. It is not an IDrawable itself, delegating sprite handling to BackgroundSceneElements. |- | BackgroundSceneElement || IDrawable. Building blocks of a bgscene. Each one represents a singular background piece, such as an iterator can, comms spire or a cloud layer. |- | CosmeticSprite || IDrawable. Particles and sprites that generally do not impact gameplay (with the exception of <code>SporeCloud</code>, which applies poison to insectoid creatures close to it). A sizeable subset of these are <code>CosmeticInsect</code>s. |- | OverseerHologram || Holograms projected by Iggy and other overseers. Cannot be used without an overseer. Instantiation code is a mess. |- | Smoke.SmokeSystem || A smoke emitter. Supports wind sway from passing creatures and explosions. |- | PhysicalObject || Too much to describe here. Gets its own [[../PhysicalObject|page]]. |} == Interfaces == <!-- Phys PhysicalObject.IHaveAppendages ILookingAtCreatures IPlayerEdible ITeleportingCreature--> These are interfaces that every UAD can implement: {| class="wikitable" |- ! Interface !! Description |- | Weapon.INotifyOfFlyingWeapons || Receives calls when there are weapons thrown in the room |- | SharedPhysics.IProjectileTracer || {{todo|target=cell}} |- | IAccessibilityModifier || Modifies pathfinding accessibility |- | ISingleCameraDrawable || An object with visuals that can only be drawn on one camera. Only implemented by ScoreLabel and would require hooks to use for a modded class |- | IDrawable || Something with visuals |- | IClimbableVine || Objects representing player-climbable ropes, such as corruption tubes. Vines are not climbable by creatures |- | INotifyWhenRoomIsReady || Receives notifications when room loading breakpoints are reached - when the room has calculated shortcut data and when the room has finished deserializing/calculating AI navmap |- | IOwnMycelia || Objects that own neural mycelia stalks{{Cn|anything else?}} |- | IOwnProjectedCircles || Objects that own iterator holo circles (they show up when a room has AI projection objects in it){{Cn|better way to describe?}} |} For interfaces that are only applicable for PhysicalObjects, see [[../PhysicalObject|this subpage]]. 857fc08f7d80191bb8fb2520ae0a6fcd85704339 Rain World Code Structure/PhysicalObject 0 195 480 2023-04-17T15:57:34Z Thalber 3 init wikitext text/x-wiki {{todo|target=page}} '''PhysicalObject'''s are main type of Realized [[../LOD|LOD]] entities and a chunky subset of [[../UpdatableAndDeletable|UADs]]. All PhysicalObjects are composed of BodyChunks. Every BodyChunk has circular collision. Each PhysicalObject begins to a collision layer, of which there are 3 (0, 1 and 2). {| class="wikitable sortable" |+ PhysicalObject useful members |- ! Member !! Kind !! Description |- | ChangeCollisionLayer || method || Sets collision layer of instance |- | collisionLayer || field || Current collision layer. Invalid value will produce error on trying to add into room |- | Collide || method || Called every time instance touches another |- | TerrainImpact || method || Called every time instance hits terrain |- | Grabbed || method || Called every time instance is grabbed by a creature |- | HitByWeapon || method || Called every time instance is hit by a throwable weapon (such as a Spear). Applying damage to creatures is handled by the weapon itself, outside of this method |- | HitByExplosion || method || Called every time instance is hit by an explosion. Applying damage to creatures is handled by the explosion itself, outside of this method |- | graphicsModule || property || Helper object that manages the instance's visuals. Not all PhysicalObject children have graphics modules (for example, most creatures do, but weapons don't) |- | InitiateGraphicsModule || method || Called when room containing instance becomes visible. Intended behavior: filling graphicsModule field (without adding it to room). |- | GraphicsModuleUpdated || method || Called every time after the Room attempts to update its graphics module |- | DisposeGraphicsModule || method || Called when room containing instance becomes no longer visible. Detaches and destroys graphics module |- | NewRoom || method || Called when instance is added to a new room{{Cn}} |- | PlaceInRoom || method || Adds instance to a selected room |- | bodyChunks || property || An array of BodyChunk objects composing instance's body. Should always be instantiated by the constructor |- | appendages || field || A list of appendages this instance has. Appendages don't directly collide with body chunks, but still collide with terrain and can be hit by weapons{{Cn}}. Should always be instantiated by the constructor. Instances with appendages should implement <code>PhysicalObject.IHaveAppendages</code> |- | bodyChunkConnections || field || Array of objects determining how different chunks are physically tied to each other. Should always be instantiated by the constructor (empty if no chunk connections) |- | Gravity || property || Gravity of object. Calculated by multiplying room-wide gravity with instance's personal g value. Setter just sets g |- | g || field || Instance's personal gravity multiplier |- | airFriction || property || Air friction determines how much instance's velocity decays every frame. Applies when out of water or partially submerged. '''IMPORTANT''': Each frame chunk velocity is ''multiplied'' by friction value, so the expected value is in range between 0 and 1, usually very close to 1. If you set this to more than 1.0f, the object will accelerate exponentially! |- | waterFriction || property || Air friction determines how much instance's velocity decays every frame. Applies when out of water or partially submerged. '''IMPORTANT''': Each frame chunk velocity is ''multiplied'' by friction value, so the expected value is in range between 0 and 1, usually very close to 1. If you set this to more than 1.0f, the object will accelerate exponentially! |- | buoyancy || property || How much water pushes the object out. 0f means no pushout (instance stays suspended), negative values make instance sink, positive make it float to the surface. |- | GoThroughFloors || property || Whether instance should fall through platforms. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithObjects || property || Whether instance should collide with other objects on the same physics layer. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithTerrain || property || Whether instance should collide with solid terrain tiles. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithSlopes || property || Whether instance should collide with slope terrain tiles. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | submersion || property || Averaged submersion of all chunks |- | VisibilityBonus || property || Value used by AI on visual contact to roll for a creature spotting the instance. Positive values mean increased likelihood, negative means reduced likelihood |- | grabbedBy || field || List of things that are grabbing instance |} == Child classes == {{todo}} == Interfaces == {{todo}} 80361000dd4dfe81caac1e9f6a31d9d98f558fbc 483 480 2023-04-17T17:40:03Z Thalber 3 Thalber moved page [[Rain World Code Structure/PhysicalObject Basics]] to [[Rain World Code Structure/PhysicalObject]] without leaving a redirect wikitext text/x-wiki {{todo|target=page}} '''PhysicalObject'''s are main type of Realized [[../LOD|LOD]] entities and a chunky subset of [[../UpdatableAndDeletable|UADs]]. All PhysicalObjects are composed of BodyChunks. Every BodyChunk has circular collision. Each PhysicalObject begins to a collision layer, of which there are 3 (0, 1 and 2). {| class="wikitable sortable" |+ PhysicalObject useful members |- ! Member !! Kind !! Description |- | ChangeCollisionLayer || method || Sets collision layer of instance |- | collisionLayer || field || Current collision layer. Invalid value will produce error on trying to add into room |- | Collide || method || Called every time instance touches another |- | TerrainImpact || method || Called every time instance hits terrain |- | Grabbed || method || Called every time instance is grabbed by a creature |- | HitByWeapon || method || Called every time instance is hit by a throwable weapon (such as a Spear). Applying damage to creatures is handled by the weapon itself, outside of this method |- | HitByExplosion || method || Called every time instance is hit by an explosion. Applying damage to creatures is handled by the explosion itself, outside of this method |- | graphicsModule || property || Helper object that manages the instance's visuals. Not all PhysicalObject children have graphics modules (for example, most creatures do, but weapons don't) |- | InitiateGraphicsModule || method || Called when room containing instance becomes visible. Intended behavior: filling graphicsModule field (without adding it to room). |- | GraphicsModuleUpdated || method || Called every time after the Room attempts to update its graphics module |- | DisposeGraphicsModule || method || Called when room containing instance becomes no longer visible. Detaches and destroys graphics module |- | NewRoom || method || Called when instance is added to a new room{{Cn}} |- | PlaceInRoom || method || Adds instance to a selected room |- | bodyChunks || property || An array of BodyChunk objects composing instance's body. Should always be instantiated by the constructor |- | appendages || field || A list of appendages this instance has. Appendages don't directly collide with body chunks, but still collide with terrain and can be hit by weapons{{Cn}}. Should always be instantiated by the constructor. Instances with appendages should implement <code>PhysicalObject.IHaveAppendages</code> |- | bodyChunkConnections || field || Array of objects determining how different chunks are physically tied to each other. Should always be instantiated by the constructor (empty if no chunk connections) |- | Gravity || property || Gravity of object. Calculated by multiplying room-wide gravity with instance's personal g value. Setter just sets g |- | g || field || Instance's personal gravity multiplier |- | airFriction || property || Air friction determines how much instance's velocity decays every frame. Applies when out of water or partially submerged. '''IMPORTANT''': Each frame chunk velocity is ''multiplied'' by friction value, so the expected value is in range between 0 and 1, usually very close to 1. If you set this to more than 1.0f, the object will accelerate exponentially! |- | waterFriction || property || Air friction determines how much instance's velocity decays every frame. Applies when out of water or partially submerged. '''IMPORTANT''': Each frame chunk velocity is ''multiplied'' by friction value, so the expected value is in range between 0 and 1, usually very close to 1. If you set this to more than 1.0f, the object will accelerate exponentially! |- | buoyancy || property || How much water pushes the object out. 0f means no pushout (instance stays suspended), negative values make instance sink, positive make it float to the surface. |- | GoThroughFloors || property || Whether instance should fall through platforms. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithObjects || property || Whether instance should collide with other objects on the same physics layer. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithTerrain || property || Whether instance should collide with solid terrain tiles. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithSlopes || property || Whether instance should collide with slope terrain tiles. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | submersion || property || Averaged submersion of all chunks |- | VisibilityBonus || property || Value used by AI on visual contact to roll for a creature spotting the instance. Positive values mean increased likelihood, negative means reduced likelihood |- | grabbedBy || field || List of things that are grabbing instance |} == Child classes == {{todo}} == Interfaces == {{todo}} 80361000dd4dfe81caac1e9f6a31d9d98f558fbc 488 483 2023-04-18T13:44:25Z Thalber 3 wikitext text/x-wiki {{todo|target=page}} '''PhysicalObject'''s are main type of Realized [[../LOD|LOD]] entities and a chunky subset of [[../UpdatableAndDeletable|UADs]]. All PhysicalObjects are composed of BodyChunks. Every BodyChunk has circular collision. Each PhysicalObject begins to a collision layer, of which there are 3 (0, 1 and 2). {| class="wikitable sortable" |+ PhysicalObject useful members |- ! Member !! Kind !! Description |- | ChangeCollisionLayer || method || Sets collision layer of instance |- | collisionLayer || field || Current collision layer. Invalid value will produce error on trying to add into room |- | Collide || method || Called every time instance touches another |- | TerrainImpact || method || Called every time instance hits terrain |- | Grabbed || method || Called every time instance is grabbed by a creature |- | HitByWeapon || method || Called every time instance is hit by a throwable weapon (such as a Spear). Applying damage to creatures is handled by the weapon itself, outside of this method |- | HitByExplosion || method || Called every time instance is hit by an explosion. Applying damage to creatures is handled by the explosion itself, outside of this method |- | graphicsModule || property || Helper object that manages the instance's visuals. Not all PhysicalObject children have graphics modules (for example, most creatures do, but weapons don't) |- | InitiateGraphicsModule || method || Called when room containing instance becomes visible. Intended behavior: filling graphicsModule field (without adding it to room). |- | GraphicsModuleUpdated || method || Called every time after the Room attempts to update its graphics module |- | DisposeGraphicsModule || method || Called when room containing instance becomes no longer visible. Detaches and destroys graphics module |- | NewRoom || method || Called when instance is added to a new room{{Cn}} |- | PlaceInRoom || method || Adds instance to a selected room |- | bodyChunks || property || An array of BodyChunk objects composing instance's body. Should always be instantiated by the constructor |- | appendages || field || A list of appendages this instance has. Appendages don't directly collide with body chunks, but still collide with terrain and can be hit by weapons{{Cn}}. Should always be instantiated by the constructor. Instances with appendages should implement <code>PhysicalObject.IHaveAppendages</code> |- | bodyChunkConnections || field || Array of objects determining how different chunks are physically tied to each other. Should always be instantiated by the constructor (empty if no chunk connections) |- | Gravity || property || Gravity of object. Calculated by multiplying room-wide gravity with instance's personal g value. Setter just sets g |- | g || field || Instance's personal gravity multiplier |- | airFriction || property || Air friction determines how much instance's velocity decays every frame. Applies when out of water or partially submerged. '''IMPORTANT''': Each frame chunk velocity is ''multiplied'' by friction value, so the expected value is in range between 0 and 1, usually very close to 1. If you set this to more than 1.0f, the object will accelerate exponentially! |- | waterFriction || property || Air friction determines how much instance's velocity decays every frame. Applies when out of water or partially submerged. '''IMPORTANT''': Each frame chunk velocity is ''multiplied'' by friction value, so the expected value is in range between 0 and 1, usually very close to 1. If you set this to more than 1.0f, the object will accelerate exponentially! |- | buoyancy || property || How much water pushes the object out. 0f means no pushout (instance stays suspended), negative values make instance sink, positive make it float to the surface. |- | GoThroughFloors || property || Whether instance should fall through platforms. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithObjects || property || Whether instance should collide with other objects on the same physics layer. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithTerrain || property || Whether instance should collide with solid terrain tiles. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithSlopes || property || Whether instance should collide with slope terrain tiles. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | submersion || property || Averaged submersion of all chunks |- | VisibilityBonus || property || Value used by AI on visual contact to roll for a creature spotting the instance. Positive values mean increased likelihood, negative means reduced likelihood |- | grabbedBy || field || List of things that are grabbing instance |} == Child classes == {{todo}} == Interfaces == <!-- Phys ILookingAtCreatures - completely fucking useless as far as i can see ~~thalber --> These are interfaces available for PhysicalObject: {| class="wikitable" |- ! Interface !! Description |- | PhysicalObject.IHaveAppendages || Implemented by objects with appendages. Required for appendages to function |- | IPlayerEdible || Implemented by things that can be bitten and consumed by all players, like noodlefly children and pupa fruits |- | ITeleportingCreature || Implemented by creatures that can teleport. In vanilla only implemented by overseers |} f9de5f19ca56ac55b26e3f1faa39a93ebaad21f4 492 488 2023-04-18T14:02:57Z Thalber 3 wikitext text/x-wiki {{todo|target=page}} '''PhysicalObject'''s are main type of Realized [[../LOD|LOD]] entities and a chunky subset of [[../UpdatableAndDeletable|UADs]]. All PhysicalObjects are composed of BodyChunks. Every BodyChunk has circular collision. Each PhysicalObject begins to a collision layer, of which there are 3 (0, 1 and 2). {| class="wikitable sortable" |+ PhysicalObject useful members |- ! Member !! Kind !! Description |- | ChangeCollisionLayer || method || Sets collision layer of instance |- | collisionLayer || field || Current collision layer. Invalid value will produce error on trying to add into room |- | Collide || method || Called every time instance touches another |- | TerrainImpact || method || Called every time instance hits terrain |- | Grabbed || method || Called every time instance is grabbed by a creature |- | HitByWeapon || method || Called every time instance is hit by a throwable weapon (such as a Spear). Applying damage to creatures is handled by the weapon itself, outside of this method |- | HitByExplosion || method || Called every time instance is hit by an explosion. Applying damage to creatures is handled by the explosion itself, outside of this method |- | graphicsModule || property || Helper object that manages the instance's visuals. Not all PhysicalObject children have graphics modules (for example, most creatures do, but weapons don't) |- | InitiateGraphicsModule || method || Called when room containing instance becomes visible. Intended behavior: filling graphicsModule field (without adding it to room). |- | GraphicsModuleUpdated || method || Called every time after the Room attempts to update its graphics module |- | DisposeGraphicsModule || method || Called when room containing instance becomes no longer visible. Detaches and destroys graphics module |- | NewRoom || method || Called when instance is added to a new room{{Cn}} |- | PlaceInRoom || method || Adds instance to a selected room |- | bodyChunks || property || An array of BodyChunk objects composing instance's body. Should always be instantiated by the constructor |- | appendages || field || A list of appendages this instance has. Appendages don't directly collide with body chunks, but still collide with terrain and can be hit by weapons{{Cn}}. Should always be instantiated by the constructor. Instances with appendages should implement <code>PhysicalObject.IHaveAppendages</code> |- | bodyChunkConnections || field || Array of objects determining how different chunks are physically tied to each other. Should always be instantiated by the constructor (empty if no chunk connections) |- | Gravity || property || Gravity of object. Calculated by multiplying room-wide gravity with instance's personal g value. Setter just sets g |- | g || field || Instance's personal gravity multiplier |- | airFriction || property || Air friction determines how much instance's velocity decays every frame. Applies when out of water or partially submerged. '''IMPORTANT''': Each frame chunk velocity is ''multiplied'' by friction value, so the expected value is in range between 0 and 1, usually very close to 1. If you set this to more than 1.0f, the object will accelerate exponentially! |- | waterFriction || property || Air friction determines how much instance's velocity decays every frame. Applies when out of water or partially submerged. '''IMPORTANT''': Each frame chunk velocity is ''multiplied'' by friction value, so the expected value is in range between 0 and 1, usually very close to 1. If you set this to more than 1.0f, the object will accelerate exponentially! |- | buoyancy || property || How much water pushes the object out. 0f means no pushout (instance stays suspended), negative values make instance sink, positive make it float to the surface. |- | GoThroughFloors || property || Whether instance should fall through platforms. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithObjects || property || Whether instance should collide with other objects on the same physics layer. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithTerrain || property || Whether instance should collide with solid terrain tiles. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | CollideWithSlopes || property || Whether instance should collide with slope terrain tiles. Can also be set on per-chunk basis, property setter here sets value for all chunks |- | submersion || property || Averaged submersion of all chunks |- | VisibilityBonus || property || Value used by AI on visual contact to roll for a creature spotting the instance. Positive values mean increased likelihood, negative means reduced likelihood |- | grabbedBy || field || List of things that are grabbing instance |} == Child classes == This section describes notable subsets of PhysicalObject. * '''OracleSwarmer''' - Different neurons * '''PlayerCarryableItem''' - Most items players can hold in one hand ** '''Weapon''' - Spears, bombs and everything else that can be thrown with force * '''[[../Creature|Creature]]''' - all realized layer creatures. Detailed info on their own page == Interfaces == <!-- Phys ILookingAtCreatures - completely fucking useless as far as i can see ~~thalber --> These are interfaces available for PhysicalObject: {| class="wikitable" |- ! Interface !! Description |- | PhysicalObject.IHaveAppendages || Implemented by objects with appendages. Required for appendages to function |- | IPlayerEdible || Implemented by things that can be bitten and consumed by all players, like noodlefly children and pupa fruits |- | ITeleportingCreature || Implemented by creatures that can teleport. In vanilla only implemented by overseers |} db817c363d6a5eeced3cf1049948b29590161ab8 Rain World Code Structure/AbstractPhysicalObject 0 196 491 2023-04-18T13:55:37Z Thalber 3 Created page with "#REDIRECT [[../AbstractWorldEntity]]" wikitext text/x-wiki #REDIRECT [[../AbstractWorldEntity]] 84eaeb8f6762818eb91f70ef98f4f9373e646418 BepInPlugins 0 95 495 390 2023-04-19T14:34:25Z RomanovIsaac 160 Updated prereqs so that it is more clear that windows is required due to the need for .NET 4.8 wikitext text/x-wiki BepInPlugins are the predominant form for Rain World code mods. They are a form of game mod native to [[BepInEx]]. They are not compatible with [[Partiality]]. == Creating a BepInPlugin == === Prerequisites === * A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary) * Rain World with RW BepInEx set up - see [[BepInEx|here]]. * Some kind of .NET programming environment, probably Visual Studio if you're on Windows. The guide below will assume you're already comfortable with the first prerequisite and your editor and environment of choice. ** The .NET Development pack for Visual Studio (including the Windows exclusive .NET Framework 4.8) === Step 1 - The project === Create a new C# .NET Framework 4.8 Class Library project in your IDE. You will then need to [https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019 add some references]. It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/core/BepInEx.dll</code> * <code>BepInEx/plugins/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/utils/PUBLIC-Assembly-CSharp.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.CoreModule.dll</code> === Step 2 - The BepInPlugin class === In a your new C# file, make a public class that has the <code>BepInEx.BepInPlugin</code> attribute and inherits from <code>BepInEx.BaseUnityPlugin</code> . The <code>BaseUnityPlugin</code> class inherits from <code>MonoBehaviour</code>, so you can use standard Unity script methods such as <code>OnEnable</code> and <code>OnDisable</code> in this class. The GUID should be unique to this plugin: something like "scholar" could be popular, which may result in BepInEx not loading your mod. Usually, people opt for the <code>username.mode_name</code> format. Include an assembly-level <code>SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)</code> declaration alongside your plugin class. This prevents errors later down the line. <syntaxhighlight lang="csharp"> using BepInEx; using System.Security.Permissions; [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] namespace SomeMod {     [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] // (GUID, mod name, mod version)     public class MyModName : BaseUnityPlugin     {     } } </syntaxhighlight> === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example:<syntaxhighlight lang="csharp"> namespace SomeMod; [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] public class MyMod : BaseUnityPlugin {     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         /* This method will be subscribed to Player.Update. */         orig(self, eu);         /* Calling orig is what allows the original method and          * other hooks to the same method do their thing.          * Not calling this is almost always undesirable, and          * can cause big issues.          *   You can execute code before or after the call of          * orig as necessary.          */     } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote>Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and find the Dynamic Link Library (DLL) file that it has compiled to. You then need to: # Create a folder and JSON for your mod, as described by [[Downpour Reference/Mod Directories]], and # Copy your mod DLL to a <code>plugins</code> folder within your mod's folder, as described by [[Downpour Reference/BepInEx Files]]. # Run the game and enable your mod by clicking on its name in the mod list in the Remix menu. Click the Apply Mods button. #* At time of writing, Rain World Remix does not support hot reloading of code mods, so the game needs to be restarted to apply your mod. == Enums == Due to their abundance in Rain World's code and their general usefulness in state machines, it's very possible that at some point you'll want to add your own value to an enum. To do that, you can use [[Downpour Reference/ExtEnum]]. == Advanced Techniques == === IL Hooking === IL hooking can be used to modify the Intermediate Language (IL) instructions of the game at runtime. This allows advanced editing of individual instructions within the game code. Risk of Thunder's guide to IL hooking can be found [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ here]. === RuntimeDetour === RuntimeDetour can be used to hook methods not covered by HOOKS-Assembly-CSharp.dll, as well as property getters and setters. A brief guide can be found on the [[MonoMod RuntimeDetour]] page. MonoMod's RuntimeDetour guide can be found [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md here]. === Harmony Patching === Harmony patching is a form of runtime patching. The HarmonyX wiki can be found [https://github.com/BepInEx/HarmonyX/wiki here]. [[Category:Code Mods]] e722a440831ea03d61e88f62c633e65a5e2a6963 496 495 2023-04-22T20:01:55Z Cashewww 2 Reverted edits by [[Special:Contributions/RomanovIsaac|RomanovIsaac]] ([[User talk:RomanovIsaac|talk]]) to last revision by [[User:Cashewww|Cashewww]] wikitext text/x-wiki BepInPlugins are the predominant form for Rain World code mods. They are a form of game mod native to [[BepInEx]]. They are not compatible with [[Partiality]]. == Creating a BepInPlugin == === Prerequisites === * A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary) * Rain World with RW BepInEx set up - see [[BepInEx|here]]. * Some kind of .NET programming environment, probably Visual Studio if you're on Windows, or Visual Studio Code for Linux/Mac. The guide below will assume you're already comfortable with the first prerequisite and your editor and environment of choice. ** The .NET Development pack for Visual Studio (or similar for other environments - you need to be able to use .NET Framework 4.8) === Step 1 - The project === Create a new C# .NET Framework 4.8 Class Library project in your IDE. You will then need to [https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019 add some references]. It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/core/BepInEx.dll</code> * <code>BepInEx/plugins/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/utils/PUBLIC-Assembly-CSharp.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.CoreModule.dll</code> === Step 2 - The BepInPlugin class === In a your new C# file, make a public class that has the <code>BepInEx.BepInPlugin</code> attribute and inherits from <code>BepInEx.BaseUnityPlugin</code> . The <code>BaseUnityPlugin</code> class inherits from <code>MonoBehaviour</code>, so you can use standard Unity script methods such as <code>OnEnable</code> and <code>OnDisable</code> in this class. The GUID should be unique to this plugin: something like "scholar" could be popular, which may result in BepInEx not loading your mod. Usually, people opt for the <code>username.mode_name</code> format. Include an assembly-level <code>SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)</code> declaration alongside your plugin class. This prevents errors later down the line. <syntaxhighlight lang="csharp"> using BepInEx; using System.Security.Permissions; [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] namespace SomeMod {     [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] // (GUID, mod name, mod version)     public class MyModName : BaseUnityPlugin     {     } } </syntaxhighlight> === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example:<syntaxhighlight lang="csharp"> namespace SomeMod; [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] public class MyMod : BaseUnityPlugin {     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         /* This method will be subscribed to Player.Update. */         orig(self, eu);         /* Calling orig is what allows the original method and          * other hooks to the same method do their thing.          * Not calling this is almost always undesirable, and          * can cause big issues.          *   You can execute code before or after the call of          * orig as necessary.          */     } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote>Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and find the Dynamic Link Library (DLL) file that it has compiled to. You then need to: # Create a folder and JSON for your mod, as described by [[Downpour Reference/Mod Directories]], and # Copy your mod DLL to a <code>plugins</code> folder within your mod's folder, as described by [[Downpour Reference/BepInEx Files]]. # Run the game and enable your mod by clicking on its name in the mod list in the Remix menu. Click the Apply Mods button. #* At time of writing, Rain World Remix does not support hot reloading of code mods, so the game needs to be restarted to apply your mod. == Enums == Due to their abundance in Rain World's code and their general usefulness in state machines, it's very possible that at some point you'll want to add your own value to an enum. To do that, you can use [[Downpour Reference/ExtEnum]]. == Advanced Techniques == === IL Hooking === IL hooking can be used to modify the Intermediate Language (IL) instructions of the game at runtime. This allows advanced editing of individual instructions within the game code. Risk of Thunder's guide to IL hooking can be found [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ here]. === RuntimeDetour === RuntimeDetour can be used to hook methods not covered by HOOKS-Assembly-CSharp.dll, as well as property getters and setters. A brief guide can be found on the [[MonoMod RuntimeDetour]] page. MonoMod's RuntimeDetour guide can be found [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md here]. === Harmony Patching === Harmony patching is a form of runtime patching. The HarmonyX wiki can be found [https://github.com/BepInEx/HarmonyX/wiki here]. [[Category:Code Mods]] 1f07f94db41806b28241796f4e95e7ebe2ad3507 BepInEx 0 98 497 161 2023-05-01T10:33:40Z Cashewww 2 marked as legacy and needing cleanup wikitext text/x-wiki {{Legacy}} {{Cleanup}} BepInEx is a mod loader and plugin framework primarily for Unity and XNA games. '''It is important to note''' that the generic BepInEx releases are not directly compatible with Partiality Mods, which make up a large portion of mods for Rain World v1.5. Currently, it is imperative you use a specially modified version of BepInEx to use the majority of existing Rain World mods. '''Another note for Linux/Steam Deck users:''' as Rain World is not natively available for Linux (and Steam Deck is powered by Linux), extra steps are required for installation. [https://gist.github.com/PJB3005/a7b635f171bd34f18a28885afa8f6e8e This guide] will help you set up Realm (a package which includes BepInEx) for Rain World on your Linux device with the help of Steam Proton/WINE. There are two ways of getting an appropriate version of BepInEx. '''Either''' use the [[#Installation|Installation]] section to install RW BepInEx '''OR''' download [https://github.com/Dual-Iron/RwModLoader#readme Realm]. Realm has an in-game mod management interface, but is currently incompatible with a small number of mods. == Installation == ''Tip: If you got the game from Steam then the default location for the Rain World folder is <code>C:\Program Files (x86)\Steam\steamapps\common\Rain World</code>, but this will be different if you changed the installation settings.'' All of the steps below for installing RW BepInEx and BOI (an app that helps manage mod files) are presented in [https://youtu.be/brDN_8uN6-U this video]. [[File:BepInEx Installation.png|alt=The BepInEx folder, doorstep_config.ini, and winhttp.dll should be in the Rain World folder. |thumb|474x474px|This is what the Rain World folder should look like after installing BepInEx. ]] If you have not installed Partiality for the current installation of Rain World, skip to step 2. # Go to the <code>Rain World/RainWorld_Data</code> folder, delete the folder called <code>Managed</code>, and rename <code>Managed_backup</code> to <code>Managed</code>. # [https://beestuff.pythonanywhere.com/audb/api/v2/bepinex/download Download RW BepInEx]. # Extract the contents of the .zip archive and copy its ''contents'' to the Rain World folder. # At this point, your Rain World folder should look like the image on the right. You can also check the installation by running the game as you normally would - if a file called LogOutput.log is now in the BepInEx folder, then BepInEx is starting up. == Using Mods == === Option 1: BOI === [[BOI]] is a graphical application for mod management with RW BepInEx. It also includes a few other tools such as save file management and ability to change [[Dev Tools]] settings. It can be installed from [https://github.com/Rain-World-Modding/BOI/releases here] - download the first .zip and extract its contents anywhere (though preferably not inside the Rain World folder). === Option 2: Realm === Realm is a package that includes BepInEx and an in-game mod management interface. It allows for download, installation, and reloading of many mods in-game. See [https://github.com/Dual-Iron/RwModLoader#readme the Realm readme] for more information. === Option 3: Moving Files === * [[BepInPlugins]] and [[Partiality|Partiality Mods]] must go in <code>BepInEx/plugins</code> * [[MonoMod Patches]] must be renamed to the format <code>Assembly-CSharp.[mod name].mm.dll</code> and must go in <code>BepInEx/monomod</code> * Preloader patchers must go in <code>BepInEx/patchers</code> 01100abc6ad6467f4eb8fcd8f5fbde75f4d601ff Level Editor 0 86 498 372 2023-05-07T21:18:29Z O645 140 /* Level Size */ wikitext text/x-wiki {{Cleanup}} == The Official Level Editor == [[File:editorFront.png|400px|thumb|right]] The Rain World level editor is a powerful tool that allows the creation of new rooms for the game, and editing existing rooms. It is the same editor the developers used to make all of the rooms for the base game. It takes specially formatted spritesheets and a number of programmed effects and outputs png files that the engine interprets in 3D (as well as an accompanying text file which contains collision and gameplay info). You can download the level editor from [https://ln.sync.com/dl/db7b0cf70/nebg7d6b-qg7gjua7-gjdi94jn-xuvivhw3/view/default/8384962820004 here.] There is also the Community Editor, which is a community-made edit of the original editor, with new features, bugfixes, and better ease of use. There is also Drizzle, a community made level renderer that's hardware accelerated. In the future it intends to replace the existing level editors. === Basic Features Overview === Once you've followed the on-screen instructions for either creating or opening a level, you are presented with the dashboard/preview screen. From here, you can switch between the different editors, load or save your level, and export it for use in-game. The preview presented here requires being manually updated whenever changes are made or when you first open a level. Pressing "1" at any point will bring you back to this screen so you can save your level or switch to a different editor. It's often best to start by modifying the dimensions of the room to your liking using the level size button before beginning to edit. You can change this at any time, but because you set the dimensions manually rather than visually, making changes later is more difficult and poses the risk of accidentally deleting a portion of your room if you aren't careful. From the dashboard you can switch to the Geometry Editor (for defining the level geometry and collision), the Tile Editor (for customizing the tiles and assets that make up the geometry created in the geometry editor), the Effects Editor (for adding procedural effects like erosion or slime, as well as things like plants or chains), the Light Editor (for customizing the light and shadow in your room), or the Prop Editor (for adding additional hand placed props and decals like graffiti). === Controls Overview === ==== View controls (numpad): ==== These are used for every editor view except the Camera and Environment editor to scroll around the screen. Notice, numlock must be turned on for these controls to have any effect. {| class="wikitable" |+ |- ! Key(s) !! Function |- | 8,2,4,6 || Moves view |- | 1 (hold) || Increases view scroll speed. |- | 3 (hold) || Increases view scroll speed even more. |- | 9 (hold) || Allow the view to move outside the boundaries of the level. |} ==== Menu keybinds (Number row): ==== These act as hotkeys to quickly switch between different editor views. These can be used in any editor view as well. {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | 1 || Main menu |- | 2 || Geometry |- | 3 || Tiles |- | 4 || Cameras |- | 5 || Light |- | 6 || Room size |} === Level Settings === ==== Level Size ==== This is where you change how big the level is. You can set the entire level size, and border tiles. Border tiles are padding around the room, mainly for resolutions that are larger than 4:3 It's recomended not to go under the defaults, or your final render will be cut off. To calculate the size your level needs to be, you can use the following formula:<br> Width = 52 * Screens + 20<br> Height = 40 * Screens + 3<br> {| class="wikitable" |+ Example Level Sizes |- ! Screens (WxH) !! Width !! Height |- | 1x1 || 72 || 43 |- | 1x2 || 72 || 83 |- | 1x3 || 72 || 123 |- | 1x4 || 72 || 163 |- | 1x5 || 72 || 203 |- | 1x6 || 72 || 243 |- | 2x1 || 124 || 43 |- | 3x1 || 176 || 43 |- | 4x1 || 228 || 43 |- | 5x1 || 280 || 43 |- | 6x1 || 332 || 43 |} ==== Default Medium ==== This determines if you can fall outside of the level or not, death pits still work the same either way however. ==== Light Type ==== The light type can either be set to '''ON''' which will use what you have done in the Light Editor, or '''OFF''' which paints everything in shadow. ==== Seed ==== This is the arrow on the fourth row of bars, which determines what seed the level will use. The seed determines random tile and prop placement, along with how effects are generated. === Rendering === ==== Prioritize Cam ==== This determines what camera will be rendered first, before starting from the beginning. Very useful for re-rendering a specific screen. ==== Text Output ==== This outputs a .txt of the level's geometry, usable in-game. ==== Render Level ==== This renders the screens ==== Mass Render ==== This will render every level in the selected folder. === Editors === <tabber> |-|Geometry Editor= == Geometry Editor == [[File: geoEditor.png|400px|thumb|right]] The Geometry Editor is the first stop for the creation of new rooms. In the Geometry Editor, you define the gameplay and collision information of your room, such as the placement of vertical and horizontal bars, shortcuts, room entrances, creature dens, and garbage worm placement. (to connect your room to other rooms), and a number of other gameplay relevant elements. === Controls === {| class="wikitable" |+ Geometry editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | Arrow keys || Primary cursor scroll through toolbox. If mouse over the toolbox, mouse moves cursor instead. |- | Mouse || Primary cursor movement. |- | LMB || Primary cursor use current tool. |- | Q (hold) || Secondary cursor scroll through toolbox. |- | E,S,D,F || Secondary cursor movement. |- | W || Secondary cursor use current tool. |} As an experimental feature, the developers implemented a second cursor and control scheme to allow two users to edit a room simultaneously (with the second user entirely on the keyboard). While this ended up being a little used feature (as far as we are aware), it is still implemented in the current editor (represented by the grey cursor). == Toolbox == {| class="wikitable" |+ Level Editor Geo Tools |- | Inverse || Flips the currently selected tile between walls, and air. |- | Paint Walls || Paints solid tiles. |- | Paint Air || Paints non-solid tiles. |- | Make Slope || Paints a slope, these can only be placed inside corners, and as the edges of larger solids. |- | Make Floor || Paints thin platforms that you can stand on, but also hold down to fall through. |- | Rect Wall || Paints solid tiles in a rectangle. Click two points to set the rectangle's dimensions and paint. |- | Rect Air || Same as above, except for non-solid tiles. |- | Worm Grass || Placed above solid ground to spawn worm grass tendrils. The number placed together to the left and right decides the height of the grass. |- | Crack Terrain || Renders as a roughly cracked fissure through the material painted on it in the tile editor. Slugcat can crawl through these tunnels. An example in the vanilla game is in the western temple styled area of the subterranean. Where there are fissures to travel beneath certain stone statues. |- | Horizontal Beam || Climbable pole. Slugcat can only climb these on layer 1. |- | Vertical Beam || Same as above, except in the other direction. |- | Glass Wall || Paints invisible solid walls. |- | Waterfall || Will cause a waterfall to appear in game, with this tile at the top of it. |} {| class="wikitable" |+ Level Editor Item and Batfly Tools |- | Place Rock || A Rock will spawn at this location with a 60% chance. |- | Place Spear ||A Spear will spawn at this location with a 60% chance. |- | Spawn Fly || Does nothing. |- | Forbid Fly Chains || Prevents bat flies from hanging together in specific locations to rest. |- | Hive || Places a bat fly hive. Bat flies can use these to quickly travel to different parts of a room. |} === Short Cuts and Entrances === [[File: shortcuts_yes.png|270px|thumb|Examples of working shortcuts]] [[File: shortcuts_no.png|270px|right|thumb|Examples of broken shortcuts]] {| class="wikitable" |+ Level Editor Shortcut Tools |- | Short Cut Entrance || Places the entrance of a short cut into the room, these must be fully surrounded by ground except from the entrance side and the exit will always be aiming in the oposite direction of the entrance. When placed on the floor, both players and creatures will fall into them, so its advised to always put a platform in the entrance instead of air in these cases. |- | Short Cut || Places a short cut's travel dot. These can connect two short cut entrances together or connect into a specific entrance or den variation. They can also have no destination, in which case the shortcut entrance will simply be blocked. Short cut dots can cross with each other in a + pattern and each path will always continue forwards. |- | Dragon Den || Places a creature den. These hold the creature assigned to that den in the region's World File. Creatures can move to the closest den if they cant return to their own. |- | Entrance || Used to connect with another room. These can be used by Slugcat and most creatures to travel across a region, the 2 rooms connected by this entrance are determined in the region's World File. |- | Scavenger Hole || Allows scavengers to spawn or travel to this room as they wander through a region. Since scavenger use offscreen dens, all the Scavenger Holes will share the same pool of scavengers. |- | Whack-A-Mole-Hole || Allows creatures to travel arround a room by "teleporting" between these holes. There is no limit to how many holes can be placed in the same room and they are all connected with each other. When a creature enters one of these holes and selects a new destination there is a short period of time in which the shortcut segment glows, so they are often used without Short Cut dots. |- | "G" Garbage Worm den || Unlike the rest of dens, its not attached to a short cut entrance. Instead they are simply placed in the ground tile where we want the Garbage Worm to spawn. |} A short cut dot is not required between the short cut's entrance and the den or door it's connecting to. However, the shortcut must show as an arrow toward the den or door for the link to it to be proper. Short cuts and their connections to the various kinds of entrances in Rain World have specific needs! Improperly making the short cut can lead to crashes, or odd behavior in game. A list of common mistakes include: * Short cuts going outside of the level bounds, anything out of the white frame won't be loaded in game. * Short cut entrances placed directly on the surface. * Short cut entrances with short cut dots on any side which isn't the opposite to the entrance. * Creature dens or room entrances randomly floating in the room disconnected from everything. * Placing Garbage Worm dens connected to an entrance like the other dens. === Layer Info === {| class="wikitable" |+ Level Editor Layer and Misc Tools |- | Copy Backwards || Copies a rectangle of tiles on the current layer to the next layer. This does not wrap around back to layer 1 if you are on layer 3. |- | Work Layer || Changes layers from 1 to 3 and then back to 1. |- | Clear All || Selects a rectangle that resets all tiles inside it, on all layers, back to open air. |- | Toggle Mirror || Turns on and off a mirror tile painting mode. What you do on one side of the mirror will be copied on the other. |- | Move Mirror || Allows you to move the location of the Mirror. |- | Move Level || Moves the whole level in a certain direction. Place the mouse cursor outside the level, then use the arrow keys to move the level in the direction you want. It will not work if your mouse is inside the level as using the arrow keys will swap to another tool. |- | Empty || Does nothing. Good to set as your tool if you have to tab out, as it does nothing. |} Rain World levels consist of 3 layers, each representing a different depth. This layer info is represented visually through the color of tiles, and you can switch between editing on different layers with the work layer tool in the bottom left of the tool panel. Layer 1 draws in full black, layer 2 draws in green, and layer 3 draws in red. These colors will blend if multiple layers are drawn on top of each other. Layer 1 is the foreground, and any filled tiles on this layer will have collision. This is the base layer you define for the sake of gameplay, as any air here is space you can traverse. Layer 2 is the midground, which you can imagine as the back wall of your room. Wall climbing creatures also interact with this. Layer 3 is the extreme background, behind the back wall of the room (for placing distant objects or giving the room a section of open sky). Nothing interacts with this at all. Note: The tile editor defines the visual tiles and props that make up this geometry, so in order to place solid objects in the tile editor (on any layer), those tiles need to be filled here in the geometry editor. Even though the mid-ground and background do not provide any collision geometry, in order to place solid props on those layers the tiles need to be filled here in the geometry editor. Similarly, some props can only be placed on air on the layers (like fences). === Tips and Tricks === - Many of the gameplay features require that they be placed within the margins of your room (represented by the white border). An entrance or creature den placed outside of your margins will render your room un-enterable at best, and crash the game at worst. Short Cut Entrances and Short Cuts can be placed outside the level boundary just fine, however. - Border tiles are tiles that can't be interacted with, and are there for looks only. The room will copy the last tile from the border forever in that direction so be careful with your geometry, or you'll be able to walk out of bounds through "solid" walls or stand in the air. - Because the tool panel loops around from top to bottom and left to right, when editing the base geometry (walls and air) it's faster to use the arrow keys to go up to reach the work layer tool to swap layers than to cycle through the whole list to reach them. Also, the rectangular wall and air tools will let you edit large chunks of your level much faster than going tile by tile. - Because the layers move with a parallax effect, it's often necessary to extend elements on your background layer behind your other layers, otherwise the camera angle will sometimes let you see a gap to the left or right of a background wall and the layer in front of it (for example). It can be just a few tiles extended, unless you have tiles infront that are transparent and reveal behind it. |-|Tile Editor= Full article here [[Tile Editor]]. {| class="wikitable" |+ Tile editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Select tile category |- | W,S || Select tile in current category |- | LMB || Place tile under cursor |- | RMB || Erase tile under cursor |- | F (hold) || Use a 3x3 brush for materials |- | V (hold) || Use a 5x5 brush for materials |- | Tab+x+c || Clears all tiles |- | L || Change active layer (1, 2, 3, loop back to 1) |- | E || Sets default material of the room to the currently selected material |- | F (hold) || Enables force placing selected tile (ignoring geometry, erasing colliding tiles) |- | G (hold) || Enables force placing selected tile (forcing appropriate geometry for the tile, erasing colliding tiles) |- | Q || "Eyedropper" (selects tile/material hovered over) |} |-|Effect Editor= Full article here [[Effects Editor]]. {| class="wikitable" |+ Effect library keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Select effect category |- | W,S || Select effect in current category |- | E || Switches to editing applied effects |- | Space || Adds selected effect to the stack |} {| class="wikitable" |+ Applied effect keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,S || Scroll through the effect stack |- | N || Switch to effect library |- | Space || Edit selected effect in the stack |} Effect editing: {| class="wikitable" |+ Effect editing keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Scroll through options in the effect's menu |- | W,S || Changes the current effect's menu |- | Space || Activates selected option in the effect's menu |- | LMB || Paints effect in the level |- | RMB || Erases effect in the level |- | R || Brush size up |- | F || Brush size down |- | E || Switch to effect stack |- | N || Switch to effect library |} |-|Camera Editor= Full article here Camera Editor. N - New camera, spawns held by mouse E - grab a camera if none is held D - Delete held camera P - Place held camera |-|Light editor= Full article here [[Light Editor]]. {| class="wikitable" |+ Light editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,A,S,D || Scale current light shape |- | Q,E || Rotate current light shape |- | Z || Toggle between drawing and erasing light |- | LMB || Paint light |- | RMB (hold) || Rotate light shape in direction of mouse ( does not paint it.) |- | R,F || Scroll through light shape library |- | J,L || Change angle of light source |- | I,K || Change distance of light source |} |-|Prop Editor= Full article here [[Prop Editor]]. {| class="wikitable" |+ Prop editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A, D || Changes prop library's category |- | W, S || Scrolls through props in current category |- | LMB || Place current prop |- | V (hold) || LMB erases highlighted prop |- | Q,E || Rotate prop left and right |- | Space (hold) || Speed up rotation |- | Y,G,H,J || Stretch prop |- | T || Reset prop stretching |- | R || reset stretching, and rotation |- | Y, H || (on wire/tube props) increases or decreases prop's physics node count. Less means more taught, more means more loose |- | X || Pause wire/tube physics |- | Tab+X+C || clear all props |- | B || Click mouse left to set the highlighted prop as the currently selected prop |- | L || Change layer |- | RMB || Cycle depth in current layer (10 sublevels). |- | Space + RMB || Cycle depth in current layer, reverse direction. |- | U,I,O,P (hold) || Freeform stretch by one of the corners (U - top right, I - bottom right, O - bottom left, and P - top left.) |- | K || resets freeform stretching. |- | N || Switches to editing properties menu of the prop. Things like forcing certain graffiti to be drawn instead of a random one. |- | M (hold) || LMB opens properties of an already placed prop instead of placing a prop (same menu as above) |- | Z || Changes prop color |- | F + LMB/RMB || Changes between prop variants. This only applies to certain props. |} |-|Environment Editor= {| class="wikitable" |+ Environment editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | L || Set water level to mouse pointer |- | F || Toggles between drawing water above the first layer or below it. |- | W || Toggle water on level |} </tabber> == Crash Avoidance and Editor Quirks == Due to the editor being extremely user unfriendly, you are likely to run into various crashes without warning. This is a list of various things to avoid doing. === Crashes: === Do not switch to editing applied effects in the Effects Editor when there are none. The switch will be invisible, and attempting to use the space bar to select something from there will crash the Level Editor. Some effects have very specific conditions and cause issues when rendering, Effects include: Thick Roots, and Shadow Plants. these ones can be okayed through until it renders.) Be sure to remove tiles from parts of a room that will be removed if you resize the room to cut those areas out, those tiles are still recorded, and will crash renders instantly. props are the exact same as above Never render with no cameras. It will crash. Always move the prop menu into an actual category when you open it, it keeps the last menu used, and crashes if you select any entry that is not a real prop. (EX: it will have the effects menu, or tile menu.) If you are using the Mirrored tile placer, in the geometry editor. Placing poles, with the other side of the mirrored brush being outside of the room, will crash the editor. === Quirks: === The main menu is a mess when you return from using the Light Editor or the Environment Editor. Just change to any other editor (geometry or tiles, and back to main menu) to clean it. This is not a crash, but will help prevent confusion if you know to expect this. To use the Move and Move Mirror tools in the editor, you must first select them, and then move your mouse outside of the room itself, before it will respond to your inputs. Usually you will only need to put your mouse over the editor, but in larger rooms, this is often an issue, as the room is "behind" the menu, and thus only changes tool selection. The editor still receives inputs if you only tab out using alt-tab. When viewing another window, it's important to always minimize the editor, because there are many things that can go wrong if you're randomly clicking in the editor. (Requires more confirmation) The screen during rendering should usually show the map being rendered, but it may not. In the task manager, The Rain World Editor is under the tab Adobe Projector. Sometimes the reason it is not showing is a second application called "Print driver host for applications". Closing the application seems to fix the issue. The window for the application may be too big to fit on screen, and cannot be fixed since reaching the top bar or right clicking cannot be accessed to move the window. === Demo and Tutorial Videos === Region Developer Kaeporo created a tutorial for creating levels in and out of the level editor: {{#ev:youtube|YQ0DO-fmPCE|||||urlargs=""}} Mod community member Sacretis also put together a demonstration video, this time covering the creation of a room from scratch to visual polish (massively sped up for the sake of time): {{#ev:youtube|sEE3X1izaJA|||||urlargs=""}} 5a63f8eb803b208713877575b8c945273aff522b 501 498 2023-05-09T19:30:35Z INVADA 173 /* The Official Level Editor */ wikitext text/x-wiki {{Cleanup}} == The Official Level Editor == [[File:editorFront.png|400px|thumb|right]] The Level Editor is an application created by the Rain World developers in order to create new in-game rooms and edit existing ones. There are two officially released versions of the editor, the [https://steamcommunity.com/app/312520/discussions/0/1700541698703118028/ original] editor used to create the base game and the [https://store.steampowered.com/news/app/312520/view/3671033323706467799 updated] editor used for the Downpour expansion. The editor functions by using specially formatted spritesheets and a number of programmed effects and outputs PNG files that the engine interprets in 3D (as well as an accompanying text file which contains collision and gameplay info). There are also several unofficial community made Level Editors, the map-editor, a editor that predated the official one and can only edit preexisting maps, the community editor, a community-made edit of the original editor, with new features, bugfixes, and better ease of use, and Drizzle, a community made level renderer that's hardware accelerated. In the future it intends to replace the existing level editors. === Basic Features Overview === Once you've opened/created a level, you are presented with the preview screen of the level, (this preview needs to be manually updated using the "update preview" button whenever changes are made to the level for it to remain accurate.) the buttons can be used to navigate between the different editors, load a new level or save/rename your current level, and export it's geometry data for use in-game. Pressing "1" will bring you back to this screen. It's often best to start by modifying the dimensions of the room to your liking using the level size button before beginning to edit. You can change this at any time, but because you set the dimensions manually rather than visually, making changes later is more difficult and poses the risk of accidentally deleting a portion of your room if you aren't careful. From the dashboard you can switch to the Geometry Editor - used for defining the level geometry and collision, the Tile Editor (for customizing the tiles and assets that make up the geometry created in the geometry editor), the Effects Editor (for adding procedural effects like erosion or slime, as well as things like plants or chains), the Light Editor - for painting light and shadow, or the Prop Editor (for adding additional hand placed props and decals like graffiti). === Controls Overview === ==== View controls (numpad): ==== These are used for every editor view except the Camera and Environment editor to scroll around the screen. Notice, numlock must be turned on for these controls to have any effect. {| class="wikitable" |+ |- ! Key(s) !! Function |- | 8,2,4,6 || Moves view |- | 1 (hold) || Increases view scroll speed. |- | 3 (hold) || Increases view scroll speed even more. |- | 9 (hold) || Allow the view to move outside the boundaries of the level. |} ==== Menu keybinds (Number row): ==== These act as hotkeys to quickly switch between different editor views. These can be used in any editor view as well. {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | 1 || Main menu |- | 2 || Geometry |- | 3 || Tiles |- | 4 || Cameras |- | 5 || Light |- | 6 || Room size |} === Level Settings === ==== Level Size ==== Allows you to set the levels dimensions. You can set the entire level size, and border tiles. Border tiles are padding around the room, mainly for resolutions that are larger than 4:3 (It is recommended to not go under the defaults numbers, as it causes the final render to be cut off.) To calculate the size your level needs to be, you can use the following formula:<br> Width = 52 * Screens + 20<br> Height = 40 * Screens + 3<br> {| class="wikitable" |+ Example Level Sizes |- ! Screens (WxH) !! Width !! Height |- | 1x1 || 72 || 43 |- | 1x2 || 72 || 83 |- | 1x3 || 72 || 123 |- | 1x4 || 72 || 163 |- | 1x5 || 72 || 203 |- | 1x6 || 72 || 243 |- | 2x1 || 124 || 43 |- | 3x1 || 176 || 43 |- | 4x1 || 228 || 43 |- | 5x1 || 280 || 43 |- | 6x1 || 332 || 43 |} ==== Default Medium ==== This determines if you can fall outside of the level or not, death pits still work the same either way however. ==== Light Type ==== The light type can either be set to '''ON''' which will use what you have done in the Light Editor, or '''OFF''' which paints everything in shadow. ==== Seed ==== This is the arrow on the fourth row of bars, which determines what seed the level will use. The seed determines random tile and prop placement, along with how effects are generated. === Rendering === ==== Prioritize Cam ==== Allows you to choose a specific camera to render first. ==== Text Output ==== This outputs a .txt of the level's geometry and collision, usable in-game. ==== Render Level ==== Renders the rooms screens. ==== Mass Render ==== Renders every level in the selected folder. === Editors === <tabber> |-|Geometry Editor= == Geometry Editor == [[File: geoEditor.png|400px|thumb|right]] In the Geometry Editor, you define the elements and collision information of your room, such as poles, shortcuts, room entrances, creature dens, and garbage worm placement. (to connect your room to other rooms), and a number of other gameplay relevant elements. === Controls === {| class="wikitable" |+ Geometry editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | Arrow keys || Primary cursor scroll through toolbox. If mouse over the toolbox, mouse moves cursor instead. |- | Mouse || Primary cursor movement. |- | LMB || Primary cursor use current tool. |- | Q (hold) || Secondary cursor scroll through toolbox. |- | E,S,D,F || Secondary cursor movement. |- | W || Secondary cursor use current tool. |} As an experimental feature, the developers implemented a second grey cursor with an alternate control scheme to allow two users to edit a room simultaneously. While as far as we are aware this ended up being a little used feature, it is still implemented and usable in the current editor == Toolbox == {| class="wikitable" |+ Level Editor Geography Tools |- | Inverse || Flips the currently selected tile between walls, and air. |- | Paint Walls || Paints solid tiles. |- | Paint Air || Paints non-solid tiles. |- | Make Slope || Paints a slope, can only be placed inside corners, or the edges of larger solids. |- | Make Floor || Paints thin platforms that entities can stand on that the player can hold down to fall through. |- | Rect Wall || Paints solid tiles in a rectangle. Click two points to set the rectangle's dimensions and paint. |- | Rect Air || Same as above, except for non-solid tiles. |- | Worm Grass || Place above solid ground to spawn worm grass tendrils. The number placed together to the left and right decides the height of the grass. |- | Crack Terrain || Renders as a roughly cracked fissure through the material painted on it in the tile editor. Slugcat can crawl through these tunnels. An example in the vanilla game is in the western temple styled area of the subterranean. Where there are fissures to travel beneath certain stone statues. |- | Horizontal Beam || A Climbable pole. Slugcat can only climb these on layer 1. |- | Vertical Beam || Same as above, except in the other direction. |- | Glass Wall || Paints invisible walls. |- | Waterfall || Will cause a waterfall to appear in game, with this tile at the top of it. |} {| class="wikitable" |+ Level Editor Item and Batfly Tools |- | Place Rock || 60% chance a Rock will spawn at this location. |- | Place Spear || 60% chance a Spear will spawn at this location. |- | Spawn Fly || Does nothing. |- | Forbid Fly Chains || Prevents batflies from hanging together in specific locations. |- | Hive || Places a batfly hive, batflies use these to quickly travel between hives. === Short Cuts and Entrances === [[File: shortcuts_yes.png|270px|thumb|Examples of working shortcuts]] [[File: shortcuts_no.png|270px|right|thumb|Examples of broken shortcuts]] {| class="wikitable" |+ Level Editor Shortcut Tools |- | Short Cut Entrance || Places the entrance of a short cut into the room, these must be fully surrounded by ground except from the entrance side and the exit will always be aiming in the oposite direction of the entrance. When placed on the floor, both players and creatures will fall into them, so its advised to always put a platform in the entrance instead of air in these cases. |- | Short Cut || Places a short cut's travel dot. These can connect two short cut entrances together or connect into a specific entrance or den variation. They can also have no destination, in which case the shortcut entrance will simply be blocked. Short cut dots can cross with each other in a + pattern and each path will always continue forwards. |- | Dragon Den || Places a creature den. These hold the creature assigned to that den in the region's World File. Creatures can move to the closest den if they cant return to their own. |- | Entrance || Used to connect with another room. These can be used by Slugcat and most creatures to travel across a region, the 2 rooms connected by this entrance are determined in the region's World File. |- | Scavenger Hole || Allows scavengers to spawn or travel to this room as they wander through a region. Since scavenger use offscreen dens, all the Scavenger Holes will share the same pool of scavengers. |- | Whack-A-Mole-Hole || Allows creatures to travel arround a room by "teleporting" between these holes. There is no limit to how many holes can be placed in the same room and they are all connected with each other. When a creature enters one of these holes and selects a new destination there is a short period of time in which the shortcut segment glows, so they are often used without Short Cut dots. |- | "G" Garbage Worm den || Unlike the rest of dens, its not attached to a short cut entrance. Instead they are simply placed in the ground tile where we want the Garbage Worm to spawn. |} A short cut dot is not required between the short cut's entrance and the den or door it's connecting to. However, the shortcut must show as an arrow toward the den or door for the link to it to be proper. Short cuts and their connections to the various kinds of entrances in Rain World have specific needs! Improperly making the short cut can lead to crashes, or odd behavior in game. A list of common mistakes include: * Short cuts going outside of the level bounds, anything out of the white frame won't be loaded in game. * Short cut entrances placed directly on the surface. * Short cut entrances with short cut dots on any side which isn't the opposite to the entrance. * Creature dens or room entrances randomly floating in the room disconnected from everything. * Placing Garbage Worm dens connected to an entrance like the other dens. === Layer Info === {| class="wikitable" |+ Level Editor Layer and Misc Tools |- | Copy Backwards || Copies a rectangle of tiles on the current layer to the next layer. This does not wrap around back to layer 1 if you are on layer 3. |- | Work Layer || Changes layers from 1 to 3 and then back to 1. |- | Clear All || Selects a rectangle that resets all tiles inside it, on all layers, back to open air. |- | Toggle Mirror || Turns on and off a mirror tile painting mode. What you do on one side of the mirror will be copied on the other. |- | Move Mirror || Allows you to move the location of the Mirror. |- | Move Level || Moves the whole level in a certain direction. Place the mouse cursor outside the level, then use the arrow keys to move the level in the direction you want. It will not work if your mouse is inside the level as using the arrow keys will swap to another tool. |- | Empty || Does nothing. Good to set as your tool if you have to tab out, as it does nothing. |} Rain World levels consist of 3 layers, each representing a different depth. This layer info is represented visually through the color of tiles, and you can switch between editing on different layers with the work layer tool in the bottom left of the tool panel. Layer 1 draws in full black, layer 2 draws in green, and layer 3 draws in red. These colors will blend if multiple layers are drawn on top of each other. Layer 1 is the foreground, and any filled tiles on this layer will have collision. This is the base layer you define for the sake of gameplay, as any air here is space you can traverse. Layer 2 is the midground, which you can imagine as the back wall of your room. Wall climbing creatures also interact with this. Layer 3 is the extreme background, behind the back wall of the room (for placing distant objects or giving the room a section of open sky). Nothing interacts with this at all. Note: The tile editor defines the visual tiles and props that make up this geometry, so in order to place solid objects in the tile editor (on any layer), those tiles need to be filled here in the geometry editor. Even though the mid-ground and background do not provide any collision geometry, in order to place solid props on those layers the tiles need to be filled here in the geometry editor. Similarly, some props can only be placed on air on the layers (like fences). === Tips and Tricks === - Many of the gameplay features require that they be placed within the margins of your room (represented by the white border). An entrance or creature den placed outside of your margins will render your room un-enterable at best, and crash the game at worst. Short Cut Entrances and Short Cuts can be placed outside the level boundary just fine, however. - Border tiles are tiles that can't be interacted with, and are there for looks only. The room will copy the last tile from the border forever in that direction so be careful with your geometry, or you'll be able to walk out of bounds through "solid" walls or stand in the air. - Because the tool panel loops around from top to bottom and left to right, when editing the base geometry (walls and air) it's faster to use the arrow keys to go up to reach the work layer tool to swap layers than to cycle through the whole list to reach them. Also, the rectangular wall and air tools will let you edit large chunks of your level much faster than going tile by tile. - Because the layers move with a parallax effect, it's often necessary to extend elements on your background layer behind your other layers, otherwise the camera angle will sometimes let you see a gap to the left or right of a background wall and the layer in front of it (for example). It can be just a few tiles extended, unless you have tiles infront that are transparent and reveal behind it. |-|Tile Editor= Full article here [[Tile Editor]]. {| class="wikitable" |+ Tile editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A-D || Flip\scroll through tile categorys |- | W-S || Select tile in current category |- | LMB || Place tile under cursor |- | RMB || Erase tile under cursor |- | F (hold) || Use a 3x3 brush for materials |- | V (hold) || Use a 5x5 brush for materials |- | Tab+x+c || Clears all tiles |- | L || Change active layer (1, 2, 3, loop back to 1) |- | E || Set default material of the room to the currently selected material. |- | F (hold) || Force places selected tile, ignores geometry and erases colliding tiles. |- | G (hold) || Enables force placing selected tile (forcing appropriate geometry for the tile, erasing colliding tiles) |- | Q || "Eyedropper" (selects tile/material hovered over) |} |-|Effect Editor= Full article here [[Effects Editor]]. {| class="wikitable" |+ Effect library keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Select effect category |- | W,S || Select effect in current category |- | E || Switches to editing applied effects |- | Space || Adds selected effect to the stack |} {| class="wikitable" |+ Applied effect keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,S || Scroll through the effect stack |- | N || Switch to effect library |- | Space || Edit selected effect in the stack |} Effect editing: {| class="wikitable" |+ Effect editing keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Scroll through options in the effect's menu |- | W,S || Changes the current effect's menu |- | Space || Activates selected option in the effect's menu |- | LMB || Paints effect in the level |- | RMB || Erases effect in the level |- | R || Brush size up |- | F || Brush size down |- | E || Switch to effect stack |- | N || Switch to effect library |} |-|Camera Editor= Full article here Camera Editor. N - New camera, spawns held by mouse E - grab a camera if none is held D - Delete held camera P - Place held camera |-|Light editor= Full article here [[Light Editor]]. {| class="wikitable" |+ Light editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,A,S,D || Scale current light shape |- | Q,E || Rotate current light shape |- | Z || Toggle between drawing and erasing light |- | LMB || Paint light |- | RMB (hold) || Rotate light shape in direction of mouse ( does not paint it.) |- | R,F || Scroll through light shape library |- | J,L || Change angle of light source |- | I,K || Change distance of light source |} |-|Prop Editor= Full article here [[Prop Editor]]. {| class="wikitable" |+ Prop editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A, D || Changes prop library's category |- | W, S || Scrolls through props in current category |- | LMB || Place current prop |- | V (hold) || LMB erases highlighted prop |- | Q,E || Rotate prop left and right |- | Space (hold) || Speed up rotation |- | Y,G,H,J || Stretch prop |- | T || Reset prop stretching |- | R || reset stretching, and rotation |- | Y, H || (on wire/tube props) increases or decreases prop's physics node count. Less means more taught, more means more loose. |- | X || Pause wire/tube physics |- | Tab+X+C || Clear all props |- | B || Click mouse left to set the highlighted prop as the currently selected prop. |- | L || Change layer |- | RMB || Cycle depth in current layer (10 sublevels). |- | Space + RMB || Cycle depth in current layer, reverse direction. |- | U-I-O-P (hold) || Freeform stretch by one of the corners (U - top right, I - bottom right, O - bottom left, and P - top left.) |- | K || resets freeform stretching. |- | N || Switches to editing properties menu of the prop. Things like forcing certain graffiti to be drawn instead of a random one. |- | M (hold) || LMB opens properties of an already placed prop instead of placing a prop (same menu as above) |- | Z || Changes prop color |- | F + LMB/RMB || Changes between prop variants. This only applies to certain props. |} |-|Environment Editor= {| class="wikitable" |+ Environment editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | L || Set water level to mouse pointer |- | F || Toggles between drawing water above the first layer or below it. |- | W || Toggle water on level |} </tabber> == Crash Avoidance and Editor Quirks == Due to the editor being extremely user unfriendly, you are likely to run into various crashes without warning. This is a list of various things to avoid doing. === Crashes: === Do not switch to editing applied effects in the Effects Editor when there are none. The switch will be invisible, and attempting to use the space bar to select something from there will crash the Level Editor. Some effects have very specific conditions and cause issues when rendering, Effects include: Thick Roots, and Shadow Plants. these ones can be okayed through until it renders.) Be sure to remove tiles from parts of a room that will be removed if you resize the room to cut those areas out, those tiles are still recorded, and will crash renders instantly. props are the exact same as above Never render with no cameras. It will crash. Always move the prop menu into an actual category when you open it, it keeps the last menu used, and crashes if you select any entry that is not a real prop. (EX: it will have the effects menu, or tile menu.) If you are using the Mirrored tile placer, in the geometry editor. Placing poles, with the other side of the mirrored brush being outside of the room, will crash the editor. === Quirks: === The main menu is a mess when you return from using the Light Editor or the Environment Editor. Just change to any other editor (geometry or tiles, and back to main menu) to clean it. This is not a crash, but will help prevent confusion if you know to expect this. To use the Move and Move Mirror tools in the editor, you must first select them, and then move your mouse outside of the room itself, before it will respond to your inputs. Usually you will only need to put your mouse over the editor, but in larger rooms, this is often an issue, as the room is "behind" the menu, and thus only changes tool selection. The editor still receives inputs if you only tab out using alt-tab. When viewing another window, it's important to always minimize the editor, because there are many things that can go wrong if you're randomly clicking in the editor. (Requires more confirmation) The screen during rendering should usually show the map being rendered, but it may not. In the task manager, The Rain World Editor is under the tab Adobe Projector. Sometimes the reason it is not showing is a second application called "Print driver host for applications". Closing the application seems to fix the issue. The window for the application may be too big to fit on screen, and cannot be fixed since reaching the top bar or right clicking cannot be accessed to move the window. === Demo and Tutorial Videos === Region Developer Kaeporo created a tutorial for creating levels in and out of the level editor: {{#ev:youtube|YQ0DO-fmPCE|||||urlargs=""}} Mod community member Sacretis also put together a demonstration video, this time covering the creation of a room from scratch to visual polish (massively sped up for the sake of time): {{#ev:youtube|sEE3X1izaJA|||||urlargs=""}} a7a377fcaf3802fe179da429fb8ab572a8e9235c 514 501 2023-06-24T15:28:23Z LimitBreaker 204 /* Editors */ wikitext text/x-wiki {{Cleanup}} == The Official Level Editor == [[File:editorFront.png|400px|thumb|right]] The Level Editor is an application created by the Rain World developers in order to create new in-game rooms and edit existing ones. There are two officially released versions of the editor, the [https://steamcommunity.com/app/312520/discussions/0/1700541698703118028/ original] editor used to create the base game and the [https://store.steampowered.com/news/app/312520/view/3671033323706467799 updated] editor used for the Downpour expansion. The editor functions by using specially formatted spritesheets and a number of programmed effects and outputs PNG files that the engine interprets in 3D (as well as an accompanying text file which contains collision and gameplay info). There are also several unofficial community made Level Editors, the map-editor, a editor that predated the official one and can only edit preexisting maps, the community editor, a community-made edit of the original editor, with new features, bugfixes, and better ease of use, and Drizzle, a community made level renderer that's hardware accelerated. In the future it intends to replace the existing level editors. === Basic Features Overview === Once you've opened/created a level, you are presented with the preview screen of the level, (this preview needs to be manually updated using the "update preview" button whenever changes are made to the level for it to remain accurate.) the buttons can be used to navigate between the different editors, load a new level or save/rename your current level, and export it's geometry data for use in-game. Pressing "1" will bring you back to this screen. It's often best to start by modifying the dimensions of the room to your liking using the level size button before beginning to edit. You can change this at any time, but because you set the dimensions manually rather than visually, making changes later is more difficult and poses the risk of accidentally deleting a portion of your room if you aren't careful. From the dashboard you can switch to the Geometry Editor - used for defining the level geometry and collision, the Tile Editor (for customizing the tiles and assets that make up the geometry created in the geometry editor), the Effects Editor (for adding procedural effects like erosion or slime, as well as things like plants or chains), the Light Editor - for painting light and shadow, or the Prop Editor (for adding additional hand placed props and decals like graffiti). === Controls Overview === ==== View controls (numpad): ==== These are used for every editor view except the Camera and Environment editor to scroll around the screen. Notice, numlock must be turned on for these controls to have any effect. {| class="wikitable" |+ |- ! Key(s) !! Function |- | 8,2,4,6 || Moves view |- | 1 (hold) || Increases view scroll speed. |- | 3 (hold) || Increases view scroll speed even more. |- | 9 (hold) || Allow the view to move outside the boundaries of the level. |} ==== Menu keybinds (Number row): ==== These act as hotkeys to quickly switch between different editor views. These can be used in any editor view as well. {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | 1 || Main menu |- | 2 || Geometry |- | 3 || Tiles |- | 4 || Cameras |- | 5 || Light |- | 6 || Room size |} === Level Settings === ==== Level Size ==== Allows you to set the levels dimensions. You can set the entire level size, and border tiles. Border tiles are padding around the room, mainly for resolutions that are larger than 4:3 (It is recommended to not go under the defaults numbers, as it causes the final render to be cut off.) To calculate the size your level needs to be, you can use the following formula:<br> Width = 52 * Screens + 20<br> Height = 40 * Screens + 3<br> {| class="wikitable" |+ Example Level Sizes |- ! Screens (WxH) !! Width !! Height |- | 1x1 || 72 || 43 |- | 1x2 || 72 || 83 |- | 1x3 || 72 || 123 |- | 1x4 || 72 || 163 |- | 1x5 || 72 || 203 |- | 1x6 || 72 || 243 |- | 2x1 || 124 || 43 |- | 3x1 || 176 || 43 |- | 4x1 || 228 || 43 |- | 5x1 || 280 || 43 |- | 6x1 || 332 || 43 |} ==== Default Medium ==== This determines if you can fall outside of the level or not, death pits still work the same either way however. ==== Light Type ==== The light type can either be set to '''ON''' which will use what you have done in the Light Editor, or '''OFF''' which paints everything in shadow. ==== Seed ==== This is the arrow on the fourth row of bars, which determines what seed the level will use. The seed determines random tile and prop placement, along with how effects are generated. === Rendering === ==== Prioritize Cam ==== Allows you to choose a specific camera to render first. ==== Text Output ==== This outputs a .txt of the level's geometry and collision, usable in-game. ==== Render Level ==== Renders the rooms screens. ==== Mass Render ==== Renders every level in the selected folder. === Editors === <tabber> |-|Geometry Editor= == Geometry Editor == [[File: geoEditor.png|400px|thumb|right]] In the Geometry Editor, you define the elements and collision information of your room, such as poles, shortcuts, room entrances, creature dens, and garbage worm placement. (to connect your room to other rooms), and a number of other gameplay relevant elements. === Controls === {| class="wikitable" |+ Geometry editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | Arrow keys || Primary cursor scroll through toolbox. If mouse over the toolbox, mouse moves cursor instead. |- | Mouse || Primary cursor movement. |- | LMB || Primary cursor use current tool. |- | Q (hold) || Secondary cursor scroll through toolbox. |- | E,S,D,F || Secondary cursor movement. |- | W || Secondary cursor use current tool. |} As an experimental feature, the developers implemented a second grey cursor with an alternate control scheme to allow two users to edit a room simultaneously. While as far as we are aware this ended up being a little used feature, it is still implemented and usable in the current editor == Toolbox == {| class="wikitable" |+ Level Editor Geography Tools |- | Inverse || Flips the currently selected tile between walls, and air. |- | Paint Walls || Paints solid tiles. |- | Paint Air || Paints non-solid tiles. |- | Make Slope || Paints a slope, can only be placed inside corners, or the edges of larger solids. |- | Make Floor || Paints thin platforms that entities can stand on that the player can hold down to fall through. |- | Rect Wall || Paints solid tiles in a rectangle. Click two points to set the rectangle's dimensions and paint. |- | Rect Air || Same as above, except for non-solid tiles. |- | Worm Grass || Place above solid ground to spawn worm grass tendrils. The number placed together to the left and right decides the height of the grass. |- | Crack Terrain || Renders as a roughly cracked fissure through the material painted on it in the tile editor. Slugcat can crawl through these tunnels. An example in the vanilla game is in the western temple styled area of the subterranean. Where there are fissures to travel beneath certain stone statues. |- | Horizontal Beam || A Climbable pole. Slugcat can only climb these on layer 1. |- | Vertical Beam || Same as above, except in the other direction. |- | Glass Wall || Paints invisible walls. |- | Waterfall || Will cause a waterfall to appear in game, with this tile at the top of it. |} {| class="wikitable" |+ Level Editor Item and Batfly Tools |- | Place Rock || 60% chance a Rock will spawn at this location. |- | Place Spear || 60% chance a Spear will spawn at this location. |- | Spawn Fly || Does nothing. |- | Forbid Fly Chains || Prevents batflies from hanging together in specific locations. |- | Hive || Places a batfly hive, batflies use these to quickly travel between hives. === Short Cuts and Entrances === [[File: shortcuts_yes.png|270px|thumb|Examples of working shortcuts]] [[File: shortcuts_no.png|270px|right|thumb|Examples of broken shortcuts]] {| class="wikitable" |+ Level Editor Shortcut Tools |- | Short Cut Entrance || Places the entrance of a short cut into the room, these must be fully surrounded by ground except from the entrance side and the exit will always be aiming in the oposite direction of the entrance. When placed on the floor, both players and creatures will fall into them, so its advised to always put a platform in the entrance instead of air in these cases. |- | Short Cut || Places a short cut's travel dot. These can connect two short cut entrances together or connect into a specific entrance or den variation. They can also have no destination, in which case the shortcut entrance will simply be blocked. Short cut dots can cross with each other in a + pattern and each path will always continue forwards. |- | Dragon Den || Places a creature den. These hold the creature assigned to that den in the region's World File. Creatures can move to the closest den if they cant return to their own. |- | Entrance || Used to connect with another room. These can be used by Slugcat and most creatures to travel across a region, the 2 rooms connected by this entrance are determined in the region's World File. |- | Scavenger Hole || Allows scavengers to spawn or travel to this room as they wander through a region. Since scavenger use offscreen dens, all the Scavenger Holes will share the same pool of scavengers. |- | Whack-A-Mole-Hole || Allows creatures to travel arround a room by "teleporting" between these holes. There is no limit to how many holes can be placed in the same room and they are all connected with each other. When a creature enters one of these holes and selects a new destination there is a short period of time in which the shortcut segment glows, so they are often used without Short Cut dots. |- | "G" Garbage Worm den || Unlike the rest of dens, its not attached to a short cut entrance. Instead they are simply placed in the ground tile where we want the Garbage Worm to spawn. |} A short cut dot is not required between the short cut's entrance and the den or door it's connecting to. However, the shortcut must show as an arrow toward the den or door for the link to it to be proper. Short cuts and their connections to the various kinds of entrances in Rain World have specific needs! Improperly making the short cut can lead to crashes, or odd behavior in game. A list of common mistakes include: * Short cuts going outside of the level bounds, anything out of the white frame won't be loaded in game. * Short cut entrances placed directly on the surface. * Short cut entrances with short cut dots on any side which isn't the opposite to the entrance. * Creature dens or room entrances randomly floating in the room disconnected from everything. * Placing Garbage Worm dens connected to an entrance like the other dens. === Layer Info === {| class="wikitable" |+ Level Editor Layer and Misc Tools |- | Copy Backwards || Copies a rectangle of tiles on the current layer to the next layer. This does not wrap around back to layer 1 if you are on layer 3. |- | Work Layer || Changes layers from 1 to 3 and then back to 1. |- | Clear All || Selects a rectangle that resets all tiles inside it, on all layers, back to open air. |- | Toggle Mirror || Turns on and off a mirror tile painting mode. What you do on one side of the mirror will be copied on the other. |- | Move Mirror || Allows you to move the location of the Mirror. |- | Move Level || Moves the whole level in a certain direction. Place the mouse cursor outside the level, then use the arrow keys to move the level in the direction you want. It will not work if your mouse is inside the level as using the arrow keys will swap to another tool. |- | Empty || Does nothing. Good to set as your tool if you have to tab out, as it does nothing. |} Rain World levels consist of 3 layers, each representing a different depth. This layer info is represented visually through the color of tiles, and you can switch between editing on different layers with the work layer tool in the bottom left of the tool panel. Layer 1 draws in full black, layer 2 draws in green, and layer 3 draws in red. These colors will blend if multiple layers are drawn on top of each other. Layer 1 is the foreground, and any filled tiles on this layer will have collision. This is the base layer you define for the sake of gameplay, as any air here is space you can traverse. Layer 2 is the midground, which you can imagine as the back wall of your room. Wall climbing creatures also interact with this. Layer 3 is the extreme background, behind the back wall of the room (for placing distant objects or giving the room a section of open sky). Nothing interacts with this at all. Note: The tile editor defines the visual tiles and props that make up this geometry, so in order to place solid objects in the tile editor (on any layer), those tiles need to be filled here in the geometry editor. Even though the mid-ground and background do not provide any collision geometry, in order to place solid props on those layers the tiles need to be filled here in the geometry editor. Similarly, some props can only be placed on air on the layers (like fences). === Tips and Tricks === - Many of the gameplay features require that they be placed within the margins of your room (represented by the white border). An entrance or creature den placed outside of your margins will render your room un-enterable at best, and crash the game at worst. Short Cut Entrances and Short Cuts can be placed outside the level boundary just fine, however. - Border tiles are tiles that can't be interacted with, and are there for looks only. The room will copy the last tile from the border forever in that direction so be careful with your geometry, or you'll be able to walk out of bounds through "solid" walls or stand in the air. - Because the tool panel loops around from top to bottom and left to right, when editing the base geometry (walls and air) it's faster to use the arrow keys to go up to reach the work layer tool to swap layers than to cycle through the whole list to reach them. Also, the rectangular wall and air tools will let you edit large chunks of your level much faster than going tile by tile. - Because the layers move with a parallax effect, it's often necessary to extend elements on your background layer behind your other layers, otherwise the camera angle will sometimes let you see a gap to the left or right of a background wall and the layer in front of it (for example). It can be just a few tiles extended, unless you have tiles infront that are transparent and reveal behind it. |-|Tile Editor= Full article here [[Tile Editor]]. {| class="wikitable" |+ Tile editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A-D || Flip\scroll through tile categorys |- | W-S || Select tile in current category |- | LMB || Place tile under cursor |- | RMB || Erase tile under cursor |- | F (hold) || Use a 3x3 brush for materials |- | V (hold) || Use a 5x5 brush for materials |- | Tab+x+c || Clears all tiles |- | L || Change active layer (1, 2, 3, loop back to 1) |- | E || Set default material of the room to the currently selected material. |- | F (hold) || Force places selected tile, ignores geometry and erases colliding tiles. |- | G (hold) || Enables force placing selected tile (forcing appropriate geometry for the tile, erasing colliding tiles) |- | Q || "Eyedropper" (selects tile/material hovered over) |} |-|Effect Editor= Full article here [[Effects Editor]]. {| class="wikitable" |+ Effect library keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Select effect category |- | W,S || Select effect in current category |- | E || Switches to editing applied effects |- | Space || Adds selected effect to the stack |} {| class="wikitable" |+ Applied effect keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,S || Scroll through the effect stack |- | N || Switch to effect library |- | Space || Edit selected effect in the stack |} Effect editing: {| class="wikitable" |+ Effect editing keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Scroll through options in the effect's menu |- | W,S || Changes the current effect's menu |- | Space || Activates selected option in the effect's menu |- | LMB || Paints effect in the level |- | RMB || Erases effect in the level |- | R || Brush size up |- | F || Brush size down |- | E || Switch to effect stack |- | N || Switch to effect library |} |-|Camera Editor= Full article here Camera Editor. N - New camera, spawns held by mouse E - grab a camera if none is held D - Delete held camera P - Place held camera Note: A maximum of 20 Cameras can be placed per level |-|Light editor= Full article here [[Light Editor]]. {| class="wikitable" |+ Light editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,A,S,D || Scale current light shape |- | Q,E || Rotate current light shape |- | Z || Toggle between drawing and erasing light |- | LMB || Paint light |- | RMB (hold) || Rotate light shape in direction of mouse ( does not paint it.) |- | R,F || Scroll through light shape library |- | J,L || Change angle of light source |- | I,K || Change distance of light source |} |-|Prop Editor= Full article here [[Prop Editor]]. {| class="wikitable" |+ Prop editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A, D || Changes prop library's category |- | W, S || Scrolls through props in current category |- | LMB || Place current prop |- | V (hold) || LMB erases highlighted prop |- | Q,E || Rotate prop left and right |- | Space (hold) || Speed up rotation |- | Y,G,H,J || Stretch prop |- | T || Reset prop stretching |- | R || reset stretching, and rotation |- | Y, H || (on wire/tube props) increases or decreases prop's physics node count. Less means more taught, more means more loose. |- | X || Pause wire/tube physics |- | Tab+X+C || Clear all props |- | B || Click mouse left to set the highlighted prop as the currently selected prop. |- | L || Change layer |- | RMB || Cycle depth in current layer (10 sublevels). |- | Space + RMB || Cycle depth in current layer, reverse direction. |- | U-I-O-P (hold) || Freeform stretch by one of the corners (U - top right, I - bottom right, O - bottom left, and P - top left.) |- | K || resets freeform stretching. |- | N || Switches to editing properties menu of the prop. Things like forcing certain graffiti to be drawn instead of a random one. |- | M (hold) || LMB opens properties of an already placed prop instead of placing a prop (same menu as above) |- | Z || Changes prop color |- | F + LMB/RMB || Changes between prop variants. This only applies to certain props. |} |-|Environment Editor= {| class="wikitable" |+ Environment editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | L || Set water level to mouse pointer |- | F || Toggles between drawing water above the first layer or below it. |- | W || Toggle water on level |} </tabber> == Crash Avoidance and Editor Quirks == Due to the editor being extremely user unfriendly, you are likely to run into various crashes without warning. This is a list of various things to avoid doing. === Crashes: === Do not switch to editing applied effects in the Effects Editor when there are none. The switch will be invisible, and attempting to use the space bar to select something from there will crash the Level Editor. Some effects have very specific conditions and cause issues when rendering, Effects include: Thick Roots, and Shadow Plants. these ones can be okayed through until it renders.) Be sure to remove tiles from parts of a room that will be removed if you resize the room to cut those areas out, those tiles are still recorded, and will crash renders instantly. props are the exact same as above Never render with no cameras. It will crash. Always move the prop menu into an actual category when you open it, it keeps the last menu used, and crashes if you select any entry that is not a real prop. (EX: it will have the effects menu, or tile menu.) If you are using the Mirrored tile placer, in the geometry editor. Placing poles, with the other side of the mirrored brush being outside of the room, will crash the editor. === Quirks: === The main menu is a mess when you return from using the Light Editor or the Environment Editor. Just change to any other editor (geometry or tiles, and back to main menu) to clean it. This is not a crash, but will help prevent confusion if you know to expect this. To use the Move and Move Mirror tools in the editor, you must first select them, and then move your mouse outside of the room itself, before it will respond to your inputs. Usually you will only need to put your mouse over the editor, but in larger rooms, this is often an issue, as the room is "behind" the menu, and thus only changes tool selection. The editor still receives inputs if you only tab out using alt-tab. When viewing another window, it's important to always minimize the editor, because there are many things that can go wrong if you're randomly clicking in the editor. (Requires more confirmation) The screen during rendering should usually show the map being rendered, but it may not. In the task manager, The Rain World Editor is under the tab Adobe Projector. Sometimes the reason it is not showing is a second application called "Print driver host for applications". Closing the application seems to fix the issue. The window for the application may be too big to fit on screen, and cannot be fixed since reaching the top bar or right clicking cannot be accessed to move the window. === Demo and Tutorial Videos === Region Developer Kaeporo created a tutorial for creating levels in and out of the level editor: {{#ev:youtube|YQ0DO-fmPCE|||||urlargs=""}} Mod community member Sacretis also put together a demonstration video, this time covering the creation of a room from scratch to visual polish (massively sped up for the sake of time): {{#ev:youtube|sEE3X1izaJA|||||urlargs=""}} 1020aca649bc17451056a9ffe2e0a14453f0eb08 User:INVADA 2 197 499 2023-05-09T15:01:39Z INVADA 173 create user page wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 File:Hi-resLE reverse(323).png 6 198 500 2023-05-09T17:21:50Z INVADA 173 wikitext text/x-wiki A high resolution version of the LE inverse sprite, recolored to be white to hopefully help with readability. god I hope wiki doesn't crunchify it 1c8ccf7b78ed9d443e66301de853a38b08437a26 Dev Tools 0 84 502 462 2023-05-09T20:08:46Z INVADA 173 /* Interface Tabs */ wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. A tip for expanding functionality can be found on the [[DebugMouse]] page. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ==Interface Tabs== Once opened the Dev Tool interface is broken up into five different tabs, <div class="wikitable"><tabber> |-| Room settings= This tab mostly contains settings for base room visuals, such as palette, cloud cover and terrain wetness. === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image below shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} [[File:Fadepalette example.png|1440px|center|border]] ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! Gameplay Lighting Decorations Insects WaterAndFlooding {|class="wikitable" |- ! '''MSC''' !! '''Effect''' !! '''Description''' !! '''Showcase''' |- !colspan="3"|Gameplay |- | style="color: green;" | No || ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | style="color: green;" | No || BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | style="color: green;" | No || SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | style="color: green;" | No || SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | style="color: green;" | No || ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | style="color: green;" | No || BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | style="color: green;" | No || DayNight || Allows the room to have a night mode. Must be used in tandem with the DayNightSettings object. |- | style="color: red;" | Yes || RoomWrap || Objects and creatures that leave one side of the room will appear on the other side as well. |- | style="color: red;" | Yes || DustWave || Makes a terrifying sandstorm sweep across the room when the rain timer runs out. |- !colspan="3"|Lighting |- | style="color: green;" | No || SkyBloom || Increases how fuzzy/bloomy the sky's light is. || [[File:Effect 2.png|frameless|Applying the effect]] |- | style="color: green;" | No || LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. || [[File:Effect 3.png|frameless]] |- | style="color: green;" | No || SkyAndLightBloom || A mix between skybloom and light burn at the same time is more intense. || [[File:Effect 4.gif|frameless|Applying the effect]] |- | style="color: green;" | No || Bloom || Similar to SkyBloom, but applies to lights. || [[File:Effect 5.png|frameless]] |- | style="color: green;" | No || Fog || Creates a white cloudy effect at layer 1. Not compatible with SkyBloom, LightBurn, SkyAndLightBloom and Bloom. || [[File:Effect 6.png|frameless]] |- | style="color: green;" | No || SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | style="color: green;" | No || ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | style="color: green;" | No || SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | style="color: green;" | No || Darkness || Darkens the room's palette. |- | style="color: green;" | No || Brightness || Brightens the room's palette. |- | style="color: green;" | No || Contrast || Increases contrast on the room's palette. |- | style="color: green;" | No || Desaturation || Desaturates the room's palette. |- | style="color: green;" | No || Hue || Shifts the hue of the room's palette. |- | style="color: green;" | No || DarkenLights || Darkens the light color on the room's palette. |- | style="color: green;" | No || WaterLights || Changes the visuals of light emitting objects that are underwater. |- !colspan="3"|Decorations |- | style="color: green;" | No || SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. || [[File:Effect 1.png|frameless|The effect at 100%]] |- | style="color: green;" | No || Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | style="color: green;" | No || BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | style="color: green;" | No || ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- | style="color: green;" | No || GreenSparks || Underhang, and the Legs' green sparkles. |- | style="color: green;" | No || VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | style="color: green;" | No || CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | style="color: green;" | No || AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | style="color: green;" | No || RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | style="color: green;" | No || VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | style="color: green;" | No || FairyParticles || Generates screen-wide particles. Should be used in tandem with the FairyParticlesSettings placed object. |- | style="color: green;" | No || Coldness || Causes slugcat to emit cold breath particles. |- | style="color: green;" | No || HeatWave || Applies a heat distortion shader over the room. |- | style="color: green;" | No || DustPuffs || Causes slugcat to emit puffs of dust under their steps. |- | style="color: green;" | No || VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | style="color: red;" | Yes || Advertisements || Overseers will show random advertisement projections. |- !colspan="3"|Insects |- | style="color: green;" | No || Flies || Spawns small flys that buzz around the room and land on objects. |- | style="color: green;" | No || FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | style="color: green;" | No || TinyDragonFly || Spawns tiny bugs that fly around plants. |- | style="color: green;" | No || RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | style="color: green;" | No || RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | style="color: green;" | No || Ant || Spawns small jumping bugs. |- | style="color: green;" | No || Beetle || Spawns small beetles that slowly fly around the room. |- | style="color: green;" | No || WaterGlowWorm || Spawns small worms that swim around in water. |- | style="color: green;" | No || Wasp || Spawns small wasps that quickly dart between walls. |- | style="color: green;" | No || Moth || Spawns small white moths which slowly flutter around the room. |- !colspan="3"|WaterAndFlooding |- | style="color: green;" | No || LightRain || Causes a gentle cosmetic version of death rain to be constantly present. |- | style="color: green;" | No || LightRain || Causes the death rain to be constantly present. Not hard enough to kill, but only to push around. |- | style="color: green;" | No || BulletRain || Causes bullet rain to be constantly present. |- | style="color: green;" | No || BulletRainFlux || Causes bullet rain to fluctuate in intensity and presence. Requires the BulletRain effect. |- | style="color: green;" | No || WaterFluxFrequency || Adjusts how fast water in the room fluctuates. |- | style="color: green;" | No || WaterFluxMinLevel || Adjusts the lowest point the water will descend to. |- | style="color: green;" | No || WaterFluxMaxLevel || Adjusts the highest point the water will rise to. |- | style="color: green;" | No || WaterFluxMinDelay || Adjusts how long the water should pause at the lowest level. |- | style="color: green;" | No || WaterFluxMaxDelay || Adjusts how long the water should pause at the highest level. |- | style="color: green;" | No || WaterFluxSpeed || Adjusts how quickly the water should fluctuate. |- | style="color: green;" | No || WaterFluxOffset || Shifts the WaterFlux cycle to happen later. |- | style="color: green;" | No || WaterFluxRumble || Adjusts how much the room should rumble while the water is fluctuating. |- | style="color: green;" | No || LethalWater || Makes water deadly to anything that touches it. |- | style="color: green;" | No || SilenceWater || Turns off the default ambient water noises. |- | style="color: green;" | No || WaterViscosity || Adjusts how thick the water is. |- | style="color: green;" | No || WaterDepth || Adjusts the visual sublayer the water appears on. Default is sublayer 0 or 1, but this effect allows the water to be placed on any sublayer, even behind the playable area. |- | style="color: red;" | Yes || InvertedWater || Puts water on the ceiling. |- | style="color: green;" | No || DirtyWater || Changes the water's appearance to be more dirty. |- | style="color: red;" | Yes || FastFloodDrain || When precycle flooding is ending, makes the room drain faster. |- | style="color: red;" | Yes || FastFloodPullDown || When precycle flooding is ending, treats the room as if it were lower. |- | style="color: green;" | No || LavaSurface || Changes the water's appearance to be more like lava. |- !colspan="3"|Unsorted |- | style="color: green;" | No || VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | style="color: green;" | No || FakeGate || Adds various dysfunctional visuals to make the room look like a gate. |- | style="color: green;" | No || PixelShift || Moves the camera center when playing in a thinner resolution. Used to keep relevant details on-screen. |- | style="color: red;" | Yes || BrokenPalette || Changes the room's palette to use the 1.5 broken palette. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom, VoidMelt </syntaxhighlight> |-| Objects= Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="24%"| '''<u>Object</u>''' !width="60%"| '''<u>Description</u>''' !width="15%"| '''Requires Reload''' |- | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | FlareBomb | Spawns a bomb. | Yes |- | PuffBall | Spawns a puffball. | Yes |- | TempleGuard | Spawns a guardian | Yes |- | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |- | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | DataPearl | Spawns a generic white pearl. | Yes |- | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | DeadVultureGrub | Same as above, except prekilled. | Yes |- | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | SporePlant | Wip | |- | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | BlueToken | Same as above, except for creature unlocks | Yes |- | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | ReliableIggyDirection | Wip | |- | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | DeadHazer | Spawns a dead Hazer. | Yes |- | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |} |-| Sounds= [[File:soundTab.png|400px|right|border|]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map= {{todo|target=tab}} [[File:mapTab.png|400px|right|border|]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections.png|400px|right|border|Connections on dev map]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png|400px|right|border|Canon view of the map]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png|400px|right|border|Example of a rendered map .png file]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers= {{todo|target=tab}} [[File:triggerTab.png|600px|right|border|Trigger tab view]] <span id="general-controls"></span> == General controls == === Save === Saves the current effects and room settings to a file inside the region’s World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by pressing R and returning to the room to see the changes. === Inherent from template === Will set the values stored in a specific template the region has to this room. === Save as template: === Saves the current room’s settings as a template for easy re-use. == Triggers Menu == '''Triggers''' are the mechanism in which some in-game events occur, such as specific songs playing, projections being displayed by the player guide overseer, or information text being displayed at the bottom of the screen. Clicking one of the four options in the bottom right-hand box will place a trigger of that type, which can be moved just like other devtools objects. === Trigger Options === Triggers have a number of settings which determine what the trigger does and under what circumstances. {| class="wikitable" |+ |- ! Trigger setting !! Description |- | Active from cycle || The minimum total cycle requirement for the trigger to activate. |- | Active up to cycle || The maximum cycle limit for the trigger to activate - if the player has a cycle count higher than this number, the trigger will not activate. |- | Fire chance || A random percentage chance for the trigger to activate, from 0% to 100%. |- | Trigger delay || How many seconds between the requirements for the trigger being met and the event occurring. |- | Karma req || The minimum karma the player needs for the trigger to activate (from 0 to 5) |- | Can only fire once/Can fire multiple times || Self-explanatory, determines whether the trigger only fires once or not. |- | No entrance requirement/Entrance XX || Determines whether the player can enter from any entrance pipe, or whether they need to come through a specific one. When an entrance is selected, a red line will connect this entrance and the options box. |- | White, Yellow, Red || Determines which gamemodes the trigger fires on - Survivor, Hunter or Monk. A gamemode’s name being displayed means that the trigger will fire in said gamemode. |} === Event Types === The lowest button on the options box lets you pick what type of event you want to add. ==== MusicEvent ==== Plays a song from the soundtrack. * The first button lets you pick the song you want to play. Files for these songs can be found in *Rain World, or many of them can be found [https://www.youtube.com/playlist?list=PLPJWSVeszYFBo1oAXYgzGfJfewnGKgGna online.] {| class="wikitable" |+ MusicEvent options |- ! Option !! Description |- | Play volume || The volume the song plays at. |- | Fade in || In seconds, how long the song takes to reach full volume. |- | Song priority || If this song’s priority is higher than another’s, then this song will continue to play if the other trigger is activated. If the priority is lower, then the higher one will play instead of it. |- | Drone volume || WIP, presumably adds a background drone sound at the set volume. |- | Fade out at threat || The threat level at which the song fades out and is overtaken by the threat music. |- | Rest cycles || If this trigger can activate multiple times, the number of cycles for the trigger to wait before being able to fire again. |- | Room transitions || How many rooms the song will continue playing through. |- | One song per cycle || Whether or not the same song can activate multiple times in one cycle. |- | Play once/loop || Determines whether the song plays once or loops |- | Continue at death || Continue playing the song when the player dies. |- | Continue through gate || Continue playing the song when the player uses a region gate. |} ==== StopMusicEvent ==== As the name says, stops one or more MusicEvents. The first button lets you pick the song you want to stop/exclude. * '''Priority:''' If a song has a higher priority than the trigger, it won’t stop. * '''Fade out:''' Same as fade in, but fading out to silence. * '''Stop all songs/stop specific song/stop all but specific song:''' Self-explanatory, song selected at the top of the box is what this refers to. ==== '''PoleMimicSubtleReveal''' ==== Causes a pole mimic to flutter slightly when activated. ==== '''ShowProjectedImageEvent''' ==== Shows player guide overseer projections ==== '''RoomSpecificTextMessage''' ==== Causes specific text prompt to appear. Prompts are hardcoded by room name {{Cn}} ==== '''BringPlayerGuideToRoom''' ==== Forces player overseer to current room === Trigger Types === * '''Spot:''' The most commonly used trigger; activates when slugcat walks into a specific circular area of the room. This is indicated by a white area-of-effect which can be moved and scaled. * '''SeeCreature:''' ''WIP, presumably activates upon a certain creature being seen.'' * '''RegionBump:''' Activates either when the region is entered or at the beginning of a cycle where the region name and cycle count is shown. * '''PreRegionBump:''' Seemingly functions the same way as RegionBump. </tabber> </div> [[Category:Dev Tools]] 8c2422dee011e0a4281136b5cbc0fa937261b5e1 504 502 2023-06-05T18:19:14Z Bro748 31 Placed Objects table update wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They can be installed from the Tools section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. A tip for expanding functionality can be found on the [[DebugMouse]] page. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ==Interface Tabs== Once opened the Dev Tool interface is broken up into five different tabs, <div class="wikitable"><tabber> |-| Room settings= This tab mostly contains settings for base room visuals, such as palette, cloud cover and terrain wetness. === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image below shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} [[File:Fadepalette example.png|1440px|center|border]] ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! Gameplay Lighting Decorations Insects WaterAndFlooding {|class="wikitable" |- ! '''MSC''' !! '''Effect''' !! '''Description''' !! '''Showcase''' |- !colspan="3"|Gameplay |- | style="color: green;" | No || ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | style="color: green;" | No || BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | style="color: green;" | No || SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | style="color: green;" | No || SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | style="color: green;" | No || ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | style="color: green;" | No || BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | style="color: green;" | No || DayNight || Allows the room to have a night mode. Must be used in tandem with the DayNightSettings object. |- | style="color: red;" | Yes || RoomWrap || Objects and creatures that leave one side of the room will appear on the other side as well. |- | style="color: red;" | Yes || DustWave || Makes a terrifying sandstorm sweep across the room when the rain timer runs out. |- !colspan="3"|Lighting |- | style="color: green;" | No || SkyBloom || Increases how fuzzy/bloomy the sky's light is. || [[File:Effect 2.png|frameless|Applying the effect]] |- | style="color: green;" | No || LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. || [[File:Effect 3.png|frameless]] |- | style="color: green;" | No || SkyAndLightBloom || A mix between skybloom and light burn at the same time is more intense. || [[File:Effect 4.gif|frameless|Applying the effect]] |- | style="color: green;" | No || Bloom || Similar to SkyBloom, but applies to lights. || [[File:Effect 5.png|frameless]] |- | style="color: green;" | No || Fog || Creates a white cloudy effect at layer 1. Not compatible with SkyBloom, LightBurn, SkyAndLightBloom and Bloom. || [[File:Effect 6.png|frameless]] |- | style="color: green;" | No || SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | style="color: green;" | No || ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | style="color: green;" | No || SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | style="color: green;" | No || Darkness || Darkens the room's palette. |- | style="color: green;" | No || Brightness || Brightens the room's palette. |- | style="color: green;" | No || Contrast || Increases contrast on the room's palette. |- | style="color: green;" | No || Desaturation || Desaturates the room's palette. |- | style="color: green;" | No || Hue || Shifts the hue of the room's palette. |- | style="color: green;" | No || DarkenLights || Darkens the light color on the room's palette. |- | style="color: green;" | No || WaterLights || Changes the visuals of light emitting objects that are underwater. |- !colspan="3"|Decorations |- | style="color: green;" | No || SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. || [[File:Effect 1.png|frameless|The effect at 100%]] |- | style="color: green;" | No || Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | style="color: green;" | No || BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | style="color: green;" | No || ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- | style="color: green;" | No || GreenSparks || Underhang, and the Legs' green sparkles. |- | style="color: green;" | No || VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | style="color: green;" | No || CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | style="color: green;" | No || AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | style="color: green;" | No || RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | style="color: green;" | No || VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | style="color: green;" | No || FairyParticles || Generates screen-wide particles. Should be used in tandem with the FairyParticlesSettings placed object. |- | style="color: green;" | No || Coldness || Causes slugcat to emit cold breath particles. |- | style="color: green;" | No || HeatWave || Applies a heat distortion shader over the room. |- | style="color: green;" | No || DustPuffs || Causes slugcat to emit puffs of dust under their steps. |- | style="color: green;" | No || VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | style="color: red;" | Yes || Advertisements || Overseers will show random advertisement projections. |- !colspan="3"|Insects |- | style="color: green;" | No || Flies || Spawns small flys that buzz around the room and land on objects. |- | style="color: green;" | No || FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | style="color: green;" | No || TinyDragonFly || Spawns tiny bugs that fly around plants. |- | style="color: green;" | No || RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | style="color: green;" | No || RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | style="color: green;" | No || Ant || Spawns small jumping bugs. |- | style="color: green;" | No || Beetle || Spawns small beetles that slowly fly around the room. |- | style="color: green;" | No || WaterGlowWorm || Spawns small worms that swim around in water. |- | style="color: green;" | No || Wasp || Spawns small wasps that quickly dart between walls. |- | style="color: green;" | No || Moth || Spawns small white moths which slowly flutter around the room. |- !colspan="3"|WaterAndFlooding |- | style="color: green;" | No || LightRain || Causes a gentle cosmetic version of death rain to be constantly present. |- | style="color: green;" | No || LightRain || Causes the death rain to be constantly present. Not hard enough to kill, but only to push around. |- | style="color: green;" | No || BulletRain || Causes bullet rain to be constantly present. |- | style="color: green;" | No || BulletRainFlux || Causes bullet rain to fluctuate in intensity and presence. Requires the BulletRain effect. |- | style="color: green;" | No || WaterFluxFrequency || Adjusts how fast water in the room fluctuates. |- | style="color: green;" | No || WaterFluxMinLevel || Adjusts the lowest point the water will descend to. |- | style="color: green;" | No || WaterFluxMaxLevel || Adjusts the highest point the water will rise to. |- | style="color: green;" | No || WaterFluxMinDelay || Adjusts how long the water should pause at the lowest level. |- | style="color: green;" | No || WaterFluxMaxDelay || Adjusts how long the water should pause at the highest level. |- | style="color: green;" | No || WaterFluxSpeed || Adjusts how quickly the water should fluctuate. |- | style="color: green;" | No || WaterFluxOffset || Shifts the WaterFlux cycle to happen later. |- | style="color: green;" | No || WaterFluxRumble || Adjusts how much the room should rumble while the water is fluctuating. |- | style="color: green;" | No || LethalWater || Makes water deadly to anything that touches it. |- | style="color: green;" | No || SilenceWater || Turns off the default ambient water noises. |- | style="color: green;" | No || WaterViscosity || Adjusts how thick the water is. |- | style="color: green;" | No || WaterDepth || Adjusts the visual sublayer the water appears on. Default is sublayer 0 or 1, but this effect allows the water to be placed on any sublayer, even behind the playable area. |- | style="color: red;" | Yes || InvertedWater || Puts water on the ceiling. |- | style="color: green;" | No || DirtyWater || Changes the water's appearance to be more dirty. |- | style="color: red;" | Yes || FastFloodDrain || When precycle flooding is ending, makes the room drain faster. |- | style="color: red;" | Yes || FastFloodPullDown || When precycle flooding is ending, treats the room as if it were lower. |- | style="color: green;" | No || LavaSurface || Changes the water's appearance to be more like lava. |- !colspan="3"|Unsorted |- | style="color: green;" | No || VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | style="color: green;" | No || FakeGate || Adds various dysfunctional visuals to make the room look like a gate. |- | style="color: green;" | No || PixelShift || Moves the camera center when playing in a thinner resolution. Used to keep relevant details on-screen. |- | style="color: red;" | Yes || BrokenPalette || Changes the room's palette to use the 1.5 broken palette. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom, VoidMelt </syntaxhighlight> |-| Objects= Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="6%"| '''<u>MSC</u>''' !width="20%"| '''<u>Object</u>''' !width="62%"| '''<u>Description</u>''' !width="12%"| '''Requires Reload''' |- !colspan="4"|Gameplay |- | style="color: green;" | No | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | style="color: green;" | No | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | style="color: green;" | No | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | style="color: green;" | No | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | style="color: green;" | No | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | style="color: green;" | No | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | style="color: green;" | No | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | style="color: green;" | No | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | style="color: green;" | No | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | style="color: green;" | No | ExitSymbolAncientShelter | Forces a door’s symbol to show as an ancient shelter room. Would be used used on the other side of gates, where you cannot control what the door links to, but still need it to show an ancient shelter room on the other side. | Yes |- | style="color: green;" | No | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | style="color: green;" | No | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |- | style="color: green;" | No | NeuronSpawner | Spawns neurons within the area | Yes |- | style="color: green;" | No | DeathFallFocus | Makes the death gradient more obvious | |- | style="color: green;" | No | Vine | Places a climbable vine in the room. | |- | style="color: red;" | Yes | KarmaShrine | Places a 'karma shrine,' which grant maximum karma on contact and recharge Saint's Ascension ability. | |- | style="color: red;" | Yes | MSArteryPush | The same as PlayerPushback, but intensity is inversly correlated with the room's gravity. That is, when there is no gravity, the push intensity is equal to PlayerPushback. When there is normal gravity, there is no push. | |- !colspan="4"|Consumable |- | style="color: green;" | No | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | style="color: green;" | No | DataPearl | Spawns a generic white pearl. | Yes |- | style="color: green;" | No | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | style="color: green;" | No | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | FlareBomb | Spawns a bomb. | Yes |- | style="color: green;" | No | PuffBall | Spawns a puffball. | Yes |- | style="color: green;" | No | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | style="color: green;" | No | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | style="color: green;" | No | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | style="color: green;" | No | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | DeadVultureGrub | Same as above, except prekilled. | Yes |- | style="color: green;" | No | SporePlant | Wip | |- | style="color: green;" | No | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | style="color: green;" | No | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | style="color: green;" | No | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | style="color: green;" | No | DeadHazer | Spawns a dead Hazer. | Yes |- | style="color: green;" | No | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | style="color: green;" | No | HangingPearls | Places a hanging pearl chain, like the ones seen on scavenger tolls. | Yes |- | style="color: green;" | No | HangingPearls | Places a hanging pearl chain, like the ones seen on scavenger tolls. | Yes |- | style="color: red;" | Yes | DandelionPeach | Places a [https://rainworld.miraheze.org/wiki/Dandelion_Peach Dandelion Peach] | Yes |- | style="color: red;" | Yes | GooieDuck | Places a [https://rainworld.miraheze.org/wiki/Gooieduck GooieDuck] | Yes |- | style="color: red;" | Yes | LillyPuck | Places a [https://rainworld.miraheze.org/wiki/Lillypuck LillyPuck] | Yes |- | style="color: red;" | Yes | GlowWeed | Places a [https://rainworld.miraheze.org/wiki/Glow_Weed Glow Weed] | Yes |- | style="color: red;" | Yes | RotFlyPaper | Places a purple rot tentacle that holds dead neurons. | Yes |- !colspan="4"|CoralBrain |- | style="color: green;" | No | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | style="color: green;" | No | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | style="color: green;" | No | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | style="color: green;" | No | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | style="color: green;" | No | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | style="color: green;" | No | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | style="color: green;" | No | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | style="color: green;" | No | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | style="color: green;" | No | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | style="color: green;" | No | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | style="color: green;" | No | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | style="color: green;" | No | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | style="color: green;" | No | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | style="color: green;" | No | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | style="color: green;" | No | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |-!colspan="4"|Decoration |- | style="color: green;" | No | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | style="color: green;" | No | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | style="color: green;" | No | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | style="color: green;" | No | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | style="color: green;" | No | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | style="color: green;" | No | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | style="color: green;" | No | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | style="color: green;" | No | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | style="color: green;" | No | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | style="color: green;" | No | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | style="color: green;" | No | FairyParticleSettings | Settings for the FairyParticles room effect | |- | style="color: green;" | No | DayNightSettings | Configures the palette for Dusk and Night | |- | style="color: green;" | No | EnergySwirl | Places a visual of swirling energy - used by MSC in the Iterator Core rooms. | No |- | style="color: green;" | No | LightningMachine | Creates electricity strands with many customizability options. | No |- | style="color: green;" | No | SteamPipe | Creates a little steam effect | Yes |- | style="color: green;" | No | WallSteamer | Creates a little steam effect | Yes |- | style="color: green;" | No | SnowSource | Adds piles of snow on top of everything in the area | No |- | style="color: green;" | No | LocalBlizzard | Creates a blizzard shader effect in the area it's placed. | No |- | style="color: green;" | No | CellDistortion | Places a fancy distortion effect. Used most commonly in Rubicon. | No |- | style="color: green;" | No | BlinkingFlower | Places a flower on the background. Used most commonly in Outer Expanse and Undergrowth | Yes |- | style="color: green;" | No | BlinkingFlower | Adds a flower to the background. Used most commonly in Outer Expanse and Undergrowth | Yes |- | style="color: red;" | Yes | OESphere | Places an orange glowing orb. | No |- !colspan="4"|Tutorial |- | style="color: green;" | No | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | style="color: green;" | No | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | style="color: green;" | No | ReliableIggyDirection | Wip | |- | style="color: green;" | No | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | style="color: green;" | No | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | style="color: green;" | No | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | style="color: green;" | No | BlueToken | Same as above, except for creature unlocks | Yes |- | style="color: Red;" | Yes | GreenToken | Same as above, except for slugcat unlocks | Yes |- | style="color: Red;" | Yes | RedToken | Same as above, except for safari unlocks | Yes |- | style="color: Red;" | Yes | WhiteToken | Places a [https://rainworld.miraheze.org/wiki/Broadcasts broadcast token] for Spearmaster | Yes |- | style="color: Red;" | Yes | DevToken | Places a [https://rainworld.miraheze.org/wiki/Developer_Commentary Dev Token] that will appear in Developer Commentary mode and will trigger the commentary | Yes |- !colspan="4"|Unsorted |- | style="color: green;" | No | TempleGuard | Spawns a guardian | Yes |- | style="color: green;" | No | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | style="color: green;" | No | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | style="color: red;" | Yes | Germinator | Does nothing, likely meant to be a consumable food type that was never implemented. | |- | style="color: red;" | Yes | BigJellyFish | Places a [https://rainworld.miraheze.org/wiki/Giant_Jellyfish Giant Jellyfish] | Yes |- | style="color: red;" | Yes | MoonCloak | Places [https://rainworld.miraheze.org/wiki/Cloak Moon's Cloak] | Yes |- | style="color: red;" | Yes | Stowaway | Places a [https://rainworld.miraheze.org/wiki/Stowaway Stowaway] | Yes |- | style="color: red;" | Yes | HRGuard | Places a Guardian that will lock all doors of the room until it is killed. | Yes |} |-| Sounds= [[File:soundTab.png|400px|right|border|]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map= {{todo|target=tab}} [[File:mapTab.png|400px|right|border|]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections.png|400px|right|border|Connections on dev map]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png|400px|right|border|Canon view of the map]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png|400px|right|border|Example of a rendered map .png file]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers= {{todo|target=tab}} [[File:triggerTab.png|600px|right|border|Trigger tab view]] <span id="general-controls"></span> == General controls == === Save === Saves the current effects and room settings to a file inside the region’s World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by pressing R and returning to the room to see the changes. === Inherent from template === Will set the values stored in a specific template the region has to this room. === Save as template: === Saves the current room’s settings as a template for easy re-use. == Triggers Menu == '''Triggers''' are the mechanism in which some in-game events occur, such as specific songs playing, projections being displayed by the player guide overseer, or information text being displayed at the bottom of the screen. Clicking one of the four options in the bottom right-hand box will place a trigger of that type, which can be moved just like other devtools objects. === Trigger Options === Triggers have a number of settings which determine what the trigger does and under what circumstances. {| class="wikitable" |+ |- ! Trigger setting !! Description |- | Active from cycle || The minimum total cycle requirement for the trigger to activate. |- | Active up to cycle || The maximum cycle limit for the trigger to activate - if the player has a cycle count higher than this number, the trigger will not activate. |- | Fire chance || A random percentage chance for the trigger to activate, from 0% to 100%. |- | Trigger delay || How many seconds between the requirements for the trigger being met and the event occurring. |- | Karma req || The minimum karma the player needs for the trigger to activate (from 0 to 5) |- | Can only fire once/Can fire multiple times || Self-explanatory, determines whether the trigger only fires once or not. |- | No entrance requirement/Entrance XX || Determines whether the player can enter from any entrance pipe, or whether they need to come through a specific one. When an entrance is selected, a red line will connect this entrance and the options box. |- | White, Yellow, Red || Determines which gamemodes the trigger fires on - Survivor, Hunter or Monk. A gamemode’s name being displayed means that the trigger will fire in said gamemode. |} === Event Types === The lowest button on the options box lets you pick what type of event you want to add. ==== MusicEvent ==== Plays a song from the soundtrack. * The first button lets you pick the song you want to play. Files for these songs can be found in *Rain World, or many of them can be found [https://www.youtube.com/playlist?list=PLPJWSVeszYFBo1oAXYgzGfJfewnGKgGna online.] {| class="wikitable" |+ MusicEvent options |- ! Option !! Description |- | Play volume || The volume the song plays at. |- | Fade in || In seconds, how long the song takes to reach full volume. |- | Song priority || If this song’s priority is higher than another’s, then this song will continue to play if the other trigger is activated. If the priority is lower, then the higher one will play instead of it. |- | Drone volume || WIP, presumably adds a background drone sound at the set volume. |- | Fade out at threat || The threat level at which the song fades out and is overtaken by the threat music. |- | Rest cycles || If this trigger can activate multiple times, the number of cycles for the trigger to wait before being able to fire again. |- | Room transitions || How many rooms the song will continue playing through. |- | One song per cycle || Whether or not the same song can activate multiple times in one cycle. |- | Play once/loop || Determines whether the song plays once or loops |- | Continue at death || Continue playing the song when the player dies. |- | Continue through gate || Continue playing the song when the player uses a region gate. |} ==== StopMusicEvent ==== As the name says, stops one or more MusicEvents. The first button lets you pick the song you want to stop/exclude. * '''Priority:''' If a song has a higher priority than the trigger, it won’t stop. * '''Fade out:''' Same as fade in, but fading out to silence. * '''Stop all songs/stop specific song/stop all but specific song:''' Self-explanatory, song selected at the top of the box is what this refers to. ==== '''PoleMimicSubtleReveal''' ==== Causes a pole mimic to flutter slightly when activated. ==== '''ShowProjectedImageEvent''' ==== Shows player guide overseer projections ==== '''RoomSpecificTextMessage''' ==== Causes specific text prompt to appear. Prompts are hardcoded by room name {{Cn}} ==== '''BringPlayerGuideToRoom''' ==== Forces player overseer to current room === Trigger Types === * '''Spot:''' The most commonly used trigger; activates when slugcat walks into a specific circular area of the room. This is indicated by a white area-of-effect which can be moved and scaled. * '''SeeCreature:''' ''WIP, presumably activates upon a certain creature being seen.'' * '''RegionBump:''' Activates either when the region is entered or at the beginning of a cycle where the region name and cycle count is shown. * '''PreRegionBump:''' Seemingly functions the same way as RegionBump. </tabber> </div> [[Category:Dev Tools]] 0414cccd851ced76be8d45f93dbf1dca4c7320bd 508 504 2023-06-20T02:12:37Z Bro748 31 /* Dev Tools */ wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They come installed with Rain World 1.9 and can be enabled in the Remix menu. For 1.5, they can be installed from the Legacy section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. A tip for expanding functionality can be found on the [[DebugMouse]] page. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ==Interface Tabs== Once opened the Dev Tool interface is broken up into five different tabs, <div class="wikitable"><tabber> |-| Room settings= This tab mostly contains settings for base room visuals, such as palette, cloud cover and terrain wetness. === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image below shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} [[File:Fadepalette example.png|1440px|center|border]] ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! Gameplay Lighting Decorations Insects WaterAndFlooding {|class="wikitable" |- ! '''MSC''' !! '''Effect''' !! '''Description''' !! '''Showcase''' |- !colspan="3"|Gameplay |- | style="color: green;" | No || ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | style="color: green;" | No || BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | style="color: green;" | No || SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | style="color: green;" | No || SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | style="color: green;" | No || ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | style="color: green;" | No || BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | style="color: green;" | No || DayNight || Allows the room to have a night mode. Must be used in tandem with the DayNightSettings object. |- | style="color: red;" | Yes || RoomWrap || Objects and creatures that leave one side of the room will appear on the other side as well. |- | style="color: red;" | Yes || DustWave || Makes a terrifying sandstorm sweep across the room when the rain timer runs out. |- !colspan="3"|Lighting |- | style="color: green;" | No || SkyBloom || Increases how fuzzy/bloomy the sky's light is. || [[File:Effect 2.png|frameless|Applying the effect]] |- | style="color: green;" | No || LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. || [[File:Effect 3.png|frameless]] |- | style="color: green;" | No || SkyAndLightBloom || A mix between skybloom and light burn at the same time is more intense. || [[File:Effect 4.gif|frameless|Applying the effect]] |- | style="color: green;" | No || Bloom || Similar to SkyBloom, but applies to lights. || [[File:Effect 5.png|frameless]] |- | style="color: green;" | No || Fog || Creates a white cloudy effect at layer 1. Not compatible with SkyBloom, LightBurn, SkyAndLightBloom and Bloom. || [[File:Effect 6.png|frameless]] |- | style="color: green;" | No || SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | style="color: green;" | No || ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | style="color: green;" | No || SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | style="color: green;" | No || Darkness || Darkens the room's palette. |- | style="color: green;" | No || Brightness || Brightens the room's palette. |- | style="color: green;" | No || Contrast || Increases contrast on the room's palette. |- | style="color: green;" | No || Desaturation || Desaturates the room's palette. |- | style="color: green;" | No || Hue || Shifts the hue of the room's palette. |- | style="color: green;" | No || DarkenLights || Darkens the light color on the room's palette. |- | style="color: green;" | No || WaterLights || Changes the visuals of light emitting objects that are underwater. |- !colspan="3"|Decorations |- | style="color: green;" | No || SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. || [[File:Effect 1.png|frameless|The effect at 100%]] |- | style="color: green;" | No || Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | style="color: green;" | No || BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | style="color: green;" | No || ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- | style="color: green;" | No || GreenSparks || Underhang, and the Legs' green sparkles. |- | style="color: green;" | No || VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | style="color: green;" | No || CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | style="color: green;" | No || AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | style="color: green;" | No || RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | style="color: green;" | No || VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | style="color: green;" | No || FairyParticles || Generates screen-wide particles. Should be used in tandem with the FairyParticlesSettings placed object. |- | style="color: green;" | No || Coldness || Causes slugcat to emit cold breath particles. |- | style="color: green;" | No || HeatWave || Applies a heat distortion shader over the room. |- | style="color: green;" | No || DustPuffs || Causes slugcat to emit puffs of dust under their steps. |- | style="color: green;" | No || VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | style="color: red;" | Yes || Advertisements || Overseers will show random advertisement projections. |- !colspan="3"|Insects |- | style="color: green;" | No || Flies || Spawns small flys that buzz around the room and land on objects. |- | style="color: green;" | No || FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | style="color: green;" | No || TinyDragonFly || Spawns tiny bugs that fly around plants. |- | style="color: green;" | No || RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | style="color: green;" | No || RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | style="color: green;" | No || Ant || Spawns small jumping bugs. |- | style="color: green;" | No || Beetle || Spawns small beetles that slowly fly around the room. |- | style="color: green;" | No || WaterGlowWorm || Spawns small worms that swim around in water. |- | style="color: green;" | No || Wasp || Spawns small wasps that quickly dart between walls. |- | style="color: green;" | No || Moth || Spawns small white moths which slowly flutter around the room. |- !colspan="3"|WaterAndFlooding |- | style="color: green;" | No || LightRain || Causes a gentle cosmetic version of death rain to be constantly present. |- | style="color: green;" | No || LightRain || Causes the death rain to be constantly present. Not hard enough to kill, but only to push around. |- | style="color: green;" | No || BulletRain || Causes bullet rain to be constantly present. |- | style="color: green;" | No || BulletRainFlux || Causes bullet rain to fluctuate in intensity and presence. Requires the BulletRain effect. |- | style="color: green;" | No || WaterFluxFrequency || Adjusts how fast water in the room fluctuates. |- | style="color: green;" | No || WaterFluxMinLevel || Adjusts the lowest point the water will descend to. |- | style="color: green;" | No || WaterFluxMaxLevel || Adjusts the highest point the water will rise to. |- | style="color: green;" | No || WaterFluxMinDelay || Adjusts how long the water should pause at the lowest level. |- | style="color: green;" | No || WaterFluxMaxDelay || Adjusts how long the water should pause at the highest level. |- | style="color: green;" | No || WaterFluxSpeed || Adjusts how quickly the water should fluctuate. |- | style="color: green;" | No || WaterFluxOffset || Shifts the WaterFlux cycle to happen later. |- | style="color: green;" | No || WaterFluxRumble || Adjusts how much the room should rumble while the water is fluctuating. |- | style="color: green;" | No || LethalWater || Makes water deadly to anything that touches it. |- | style="color: green;" | No || SilenceWater || Turns off the default ambient water noises. |- | style="color: green;" | No || WaterViscosity || Adjusts how thick the water is. |- | style="color: green;" | No || WaterDepth || Adjusts the visual sublayer the water appears on. Default is sublayer 0 or 1, but this effect allows the water to be placed on any sublayer, even behind the playable area. |- | style="color: red;" | Yes || InvertedWater || Puts water on the ceiling. |- | style="color: green;" | No || DirtyWater || Changes the water's appearance to be more dirty. |- | style="color: red;" | Yes || FastFloodDrain || When precycle flooding is ending, makes the room drain faster. |- | style="color: red;" | Yes || FastFloodPullDown || When precycle flooding is ending, treats the room as if it were lower. |- | style="color: green;" | No || LavaSurface || Changes the water's appearance to be more like lava. |- !colspan="3"|Unsorted |- | style="color: green;" | No || VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | style="color: green;" | No || FakeGate || Adds various dysfunctional visuals to make the room look like a gate. |- | style="color: green;" | No || PixelShift || Moves the camera center when playing in a thinner resolution. Used to keep relevant details on-screen. |- | style="color: red;" | Yes || BrokenPalette || Changes the room's palette to use the 1.5 broken palette. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom, VoidMelt </syntaxhighlight> |-| Objects= Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="6%"| '''<u>MSC</u>''' !width="20%"| '''<u>Object</u>''' !width="62%"| '''<u>Description</u>''' !width="12%"| '''Requires Reload''' |- !colspan="4"|Gameplay |- | style="color: green;" | No | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | style="color: green;" | No | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | style="color: green;" | No | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | style="color: green;" | No | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | style="color: green;" | No | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | style="color: green;" | No | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | style="color: green;" | No | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | style="color: green;" | No | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | style="color: green;" | No | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | style="color: green;" | No | ExitSymbolAncientShelter | Forces a door’s symbol to show as an ancient shelter room. Would be used used on the other side of gates, where you cannot control what the door links to, but still need it to show an ancient shelter room on the other side. | Yes |- | style="color: green;" | No | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | style="color: green;" | No | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |- | style="color: green;" | No | NeuronSpawner | Spawns neurons within the area | Yes |- | style="color: green;" | No | DeathFallFocus | Makes the death gradient more obvious | |- | style="color: green;" | No | Vine | Places a climbable vine in the room. | |- | style="color: red;" | Yes | KarmaShrine | Places a 'karma shrine,' which grant maximum karma on contact and recharge Saint's Ascension ability. | |- | style="color: red;" | Yes | MSArteryPush | The same as PlayerPushback, but intensity is inversly correlated with the room's gravity. That is, when there is no gravity, the push intensity is equal to PlayerPushback. When there is normal gravity, there is no push. | |- !colspan="4"|Consumable |- | style="color: green;" | No | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | style="color: green;" | No | DataPearl | Spawns a generic white pearl. | Yes |- | style="color: green;" | No | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | style="color: green;" | No | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | FlareBomb | Spawns a bomb. | Yes |- | style="color: green;" | No | PuffBall | Spawns a puffball. | Yes |- | style="color: green;" | No | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | style="color: green;" | No | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | style="color: green;" | No | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | style="color: green;" | No | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | DeadVultureGrub | Same as above, except prekilled. | Yes |- | style="color: green;" | No | SporePlant | Wip | |- | style="color: green;" | No | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | style="color: green;" | No | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | style="color: green;" | No | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | style="color: green;" | No | DeadHazer | Spawns a dead Hazer. | Yes |- | style="color: green;" | No | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | style="color: green;" | No | HangingPearls | Places a hanging pearl chain, like the ones seen on scavenger tolls. | Yes |- | style="color: green;" | No | HangingPearls | Places a hanging pearl chain, like the ones seen on scavenger tolls. | Yes |- | style="color: red;" | Yes | DandelionPeach | Places a [https://rainworld.miraheze.org/wiki/Dandelion_Peach Dandelion Peach] | Yes |- | style="color: red;" | Yes | GooieDuck | Places a [https://rainworld.miraheze.org/wiki/Gooieduck GooieDuck] | Yes |- | style="color: red;" | Yes | LillyPuck | Places a [https://rainworld.miraheze.org/wiki/Lillypuck LillyPuck] | Yes |- | style="color: red;" | Yes | GlowWeed | Places a [https://rainworld.miraheze.org/wiki/Glow_Weed Glow Weed] | Yes |- | style="color: red;" | Yes | RotFlyPaper | Places a purple rot tentacle that holds dead neurons. | Yes |- !colspan="4"|CoralBrain |- | style="color: green;" | No | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | style="color: green;" | No | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | style="color: green;" | No | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | style="color: green;" | No | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | style="color: green;" | No | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | style="color: green;" | No | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | style="color: green;" | No | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | style="color: green;" | No | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | style="color: green;" | No | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | style="color: green;" | No | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | style="color: green;" | No | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | style="color: green;" | No | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | style="color: green;" | No | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | style="color: green;" | No | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | style="color: green;" | No | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |-!colspan="4"|Decoration |- | style="color: green;" | No | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | style="color: green;" | No | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | style="color: green;" | No | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | style="color: green;" | No | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | style="color: green;" | No | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | style="color: green;" | No | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | style="color: green;" | No | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | style="color: green;" | No | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | style="color: green;" | No | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | style="color: green;" | No | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | style="color: green;" | No | FairyParticleSettings | Settings for the FairyParticles room effect | |- | style="color: green;" | No | DayNightSettings | Configures the palette for Dusk and Night | |- | style="color: green;" | No | EnergySwirl | Places a visual of swirling energy - used by MSC in the Iterator Core rooms. | No |- | style="color: green;" | No | LightningMachine | Creates electricity strands with many customizability options. | No |- | style="color: green;" | No | SteamPipe | Creates a little steam effect | Yes |- | style="color: green;" | No | WallSteamer | Creates a little steam effect | Yes |- | style="color: green;" | No | SnowSource | Adds piles of snow on top of everything in the area | No |- | style="color: green;" | No | LocalBlizzard | Creates a blizzard shader effect in the area it's placed. | No |- | style="color: green;" | No | CellDistortion | Places a fancy distortion effect. Used most commonly in Rubicon. | No |- | style="color: green;" | No | BlinkingFlower | Places a flower on the background. Used most commonly in Outer Expanse and Undergrowth | Yes |- | style="color: green;" | No | BlinkingFlower | Adds a flower to the background. Used most commonly in Outer Expanse and Undergrowth | Yes |- | style="color: red;" | Yes | OESphere | Places an orange glowing orb. | No |- !colspan="4"|Tutorial |- | style="color: green;" | No | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | style="color: green;" | No | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | style="color: green;" | No | ReliableIggyDirection | Wip | |- | style="color: green;" | No | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | style="color: green;" | No | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | style="color: green;" | No | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | style="color: green;" | No | BlueToken | Same as above, except for creature unlocks | Yes |- | style="color: Red;" | Yes | GreenToken | Same as above, except for slugcat unlocks | Yes |- | style="color: Red;" | Yes | RedToken | Same as above, except for safari unlocks | Yes |- | style="color: Red;" | Yes | WhiteToken | Places a [https://rainworld.miraheze.org/wiki/Broadcasts broadcast token] for Spearmaster | Yes |- | style="color: Red;" | Yes | DevToken | Places a [https://rainworld.miraheze.org/wiki/Developer_Commentary Dev Token] that will appear in Developer Commentary mode and will trigger the commentary | Yes |- !colspan="4"|Unsorted |- | style="color: green;" | No | TempleGuard | Spawns a guardian | Yes |- | style="color: green;" | No | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | style="color: green;" | No | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | style="color: red;" | Yes | Germinator | Does nothing, likely meant to be a consumable food type that was never implemented. | |- | style="color: red;" | Yes | BigJellyFish | Places a [https://rainworld.miraheze.org/wiki/Giant_Jellyfish Giant Jellyfish] | Yes |- | style="color: red;" | Yes | MoonCloak | Places [https://rainworld.miraheze.org/wiki/Cloak Moon's Cloak] | Yes |- | style="color: red;" | Yes | Stowaway | Places a [https://rainworld.miraheze.org/wiki/Stowaway Stowaway] | Yes |- | style="color: red;" | Yes | HRGuard | Places a Guardian that will lock all doors of the room until it is killed. | Yes |} |-| Sounds= [[File:soundTab.png|400px|right|border|]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map= {{todo|target=tab}} [[File:mapTab.png|400px|right|border|]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections.png|400px|right|border|Connections on dev map]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png|400px|right|border|Canon view of the map]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png|400px|right|border|Example of a rendered map .png file]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers= {{todo|target=tab}} [[File:triggerTab.png|600px|right|border|Trigger tab view]] <span id="general-controls"></span> == General controls == === Save === Saves the current effects and room settings to a file inside the region’s World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by pressing R and returning to the room to see the changes. === Inherent from template === Will set the values stored in a specific template the region has to this room. === Save as template: === Saves the current room’s settings as a template for easy re-use. == Triggers Menu == '''Triggers''' are the mechanism in which some in-game events occur, such as specific songs playing, projections being displayed by the player guide overseer, or information text being displayed at the bottom of the screen. Clicking one of the four options in the bottom right-hand box will place a trigger of that type, which can be moved just like other devtools objects. === Trigger Options === Triggers have a number of settings which determine what the trigger does and under what circumstances. {| class="wikitable" |+ |- ! Trigger setting !! Description |- | Active from cycle || The minimum total cycle requirement for the trigger to activate. |- | Active up to cycle || The maximum cycle limit for the trigger to activate - if the player has a cycle count higher than this number, the trigger will not activate. |- | Fire chance || A random percentage chance for the trigger to activate, from 0% to 100%. |- | Trigger delay || How many seconds between the requirements for the trigger being met and the event occurring. |- | Karma req || The minimum karma the player needs for the trigger to activate (from 0 to 5) |- | Can only fire once/Can fire multiple times || Self-explanatory, determines whether the trigger only fires once or not. |- | No entrance requirement/Entrance XX || Determines whether the player can enter from any entrance pipe, or whether they need to come through a specific one. When an entrance is selected, a red line will connect this entrance and the options box. |- | White, Yellow, Red || Determines which gamemodes the trigger fires on - Survivor, Hunter or Monk. A gamemode’s name being displayed means that the trigger will fire in said gamemode. |} === Event Types === The lowest button on the options box lets you pick what type of event you want to add. ==== MusicEvent ==== Plays a song from the soundtrack. * The first button lets you pick the song you want to play. Files for these songs can be found in *Rain World, or many of them can be found [https://www.youtube.com/playlist?list=PLPJWSVeszYFBo1oAXYgzGfJfewnGKgGna online.] {| class="wikitable" |+ MusicEvent options |- ! Option !! Description |- | Play volume || The volume the song plays at. |- | Fade in || In seconds, how long the song takes to reach full volume. |- | Song priority || If this song’s priority is higher than another’s, then this song will continue to play if the other trigger is activated. If the priority is lower, then the higher one will play instead of it. |- | Drone volume || WIP, presumably adds a background drone sound at the set volume. |- | Fade out at threat || The threat level at which the song fades out and is overtaken by the threat music. |- | Rest cycles || If this trigger can activate multiple times, the number of cycles for the trigger to wait before being able to fire again. |- | Room transitions || How many rooms the song will continue playing through. |- | One song per cycle || Whether or not the same song can activate multiple times in one cycle. |- | Play once/loop || Determines whether the song plays once or loops |- | Continue at death || Continue playing the song when the player dies. |- | Continue through gate || Continue playing the song when the player uses a region gate. |} ==== StopMusicEvent ==== As the name says, stops one or more MusicEvents. The first button lets you pick the song you want to stop/exclude. * '''Priority:''' If a song has a higher priority than the trigger, it won’t stop. * '''Fade out:''' Same as fade in, but fading out to silence. * '''Stop all songs/stop specific song/stop all but specific song:''' Self-explanatory, song selected at the top of the box is what this refers to. ==== '''PoleMimicSubtleReveal''' ==== Causes a pole mimic to flutter slightly when activated. ==== '''ShowProjectedImageEvent''' ==== Shows player guide overseer projections ==== '''RoomSpecificTextMessage''' ==== Causes specific text prompt to appear. Prompts are hardcoded by room name {{Cn}} ==== '''BringPlayerGuideToRoom''' ==== Forces player overseer to current room === Trigger Types === * '''Spot:''' The most commonly used trigger; activates when slugcat walks into a specific circular area of the room. This is indicated by a white area-of-effect which can be moved and scaled. * '''SeeCreature:''' ''WIP, presumably activates upon a certain creature being seen.'' * '''RegionBump:''' Activates either when the region is entered or at the beginning of a cycle where the region name and cycle count is shown. * '''PreRegionBump:''' Seemingly functions the same way as RegionBump. </tabber> </div> [[Category:Dev Tools]] 49e930f9b374cbe248b4f64770139e8a731755db Region From The Ground Up 0 136 503 342 2023-05-25T17:20:10Z Bro748 31 Updating for 1.9 file format changes wikitext text/x-wiki {{Cleanup}} {{todo|target=page}} So you want to make a region, but you have no clue where to start! The idea of modding something so big is certainly daunting! However, looking at everything in small repeatable pieces will let you work step by step until one day you’ll suddenly have a finished region! However before that happens you need to learn some basics to get you started! Lets start with some terminology of the tools used! * [[Level Editor]] - This is the tool given to the modding community by the Rain World developers. These are the actual tools used to make Rain World. However much of its features and hotkeys are difficult and quirky to work with at first, but given enough time and use, the editor becomes an extremely powerful tool. * Unofficial level editor - This is a tool created by AndrewFM and Mikronaut to edit Rain World rooms before the official editor was released. While it lacks many features needed to make rooms. It does have the incredibly useful feature of being able to edit already exported rooms. As well as changing creature dens into doors, and vice versa. * [[Dev Tools]] - These are in game tools Rain World uses for editing room visual effects, sounds, and triggers. As well as the regions map, and the various other specific configurations of your room! * [[World File Format]] - This controls how your region (or any other region!) binds rooms together. As well as creature spawns! * Room settings text - These files are present for every room that you save a configuration for in the dev tools. It contains the placement of objects, sounds, room effects, and any other setting applied using the dev tools. I will not be giving a full control outline for every editor in this tutorial. If you need the editor’s controls, please see the full article on the specific tool you are using for their list of inputs and quirks. This article is an exercise in how to bring a level from an empty screen, to a fully fleshed out room. Largely following my own process. Don’t be afraid to branch out and try weirder things as you get comfortable with the editor! == Important terms and info == * A region is a large collection of connected rooms. Using a Worldfile to setup data inside them. * A room is stored as several files that contain: ** Geometry and pathfinding data ** Room graphics, one .PNG file per camera ** Settings file containing additional data such as room effects, sound triggers and placed objects (defined in [[Dev Tools]]) * The editor can only export the collision and graphics for rooms, Dev Tools are used to set the colors and effects. * Every room needs at least one valid door in order to be connected * By default, the editor will create a room the correct size for a single screen, with a single camera already set up. <!--This is why the guide assumes only a single screen to help you learn to use the editor.--> By default, a single room is 72 x 43. '''Changing room size after some tiles have been added breaks the tiles, and has a chance of corrupting the level project with uneraseable invisible tiles!''' == Setting Up == [[File:rfg-1.png|thumb|none|alt=1|1]] Once you open the official editor for the first time. you will be greeted with a file select. It is advised to make a folder for your rooms to keep them organized before you open the editor. Use the arrow keys to navigate into that folder, and press N to make a new room. You will then be greeted with the editor’s main menu. === Saving, and name quirks: === Before we do anything, lets save our room. It is REQUIRED that you start all of your rooms names with a region prefix. You can check the Rain World, World folder for the regions in game. We will be using SU_ the prefix for outskirts, at least until we have several rooms for our region later, or you are confident enough to begin making rooms for your own region. Secondly, NEVER use spaces. Always use an underscore _ to separate your name’s sections. Examples of correct room names: * SU_test01 * SU_myroom * SU_my_room * SU_another_room * SU_lotsandlotsofroom15 * SU_A04 The developers often used the letter (A, B, C…, J…) after the underscore _ to track the number of cameras in the room (for non-shelter (S) rooms), but this is not required. Examples of actual rooms in the game: * SU_A05 - small Outskirts room with 1 camera (A) * SU_B08 - larger Outskirts room with 2 cameras (B) * HI_C14 - wide Industrial Complex room with 3 cameras (C) * CC_D01 - tall Chimney Canopy room with 4 cameras (D) * SL_F01 - Shoreline room with 6 cameras (F) * UW_J01 - huge room in The Wall with 10 cameras (J) So now. You are ready to begin painting! == A Blank Canvas == [[File:rfg-2.png|thumb|none|alt=2|2]] Click the geometry editor button to begin painting your level’s basic geometry. However, before we do anything. We will first clear all the layer using the “clear all” tool. Use the arrow keys while the mouse is over the tile grid to change tools. Once the red box is over the X shaped tool. Used the numpad to navigate to the top left corner, click once to start drawing the rectangle of the clear tool, and navigate to the bottom right to place the other corner. When you are finished all the solid walls in the room will be removed. Leaving you with a completely blank canvas to work from. A “fuzzy” grey border marks the very edge of a room. Where tiles no longer exist to the game. The white rectangle is the game play border Anything outside of this will repeat off into the distance, this ONLY applies to the room’s collision. Visually they will be fine. All room in Rain World use these borders. For a more simple explanation. Keep everything related to gameplay inside the white rectangle! Anything outside will only show up visually, but will not act the same as they would inside the rectangle! == Blocking It Out == [[File:rfg-3.png|thumb|none|alt=3|3]] Lets start painting out the shapes we want for our basic level! This seems like a bit sudden of a jump, but only a few moments of messing around in the editor will let you achieve what you see in the screenshot! Short cuts to doors and dens require walls to be placed in specific ways around them. The [[Level Editor#Editors|Geometry Editor]] article goes into more depth about properly connecting short cuts, doors, and dens. For now, we will simply place walls, some poles, and at least one “Entrance” to the room. The Dens seen in the screenshot are optional. Only one door is required for this tutorial. == A Test Render == [[File:rfg-4.png|thumb|none|alt=4|4]] Before we move on; Lets do another save. So if anything goes wrong we won’t lose the level geometry we now have. Press 1 on the number row to return to the main menu, and press the save button! Press enter in the name field to save the room without changing the name of it. It is now time to do a test render of our room so we can see if it plays correctly in game! First, we need to click “Text Output” to save the levels collision data, and then press “Render Level.” The editor will appear to freeze for a few moments. This is normal! Do not be worried, or attempt to close the editor! Eventually the editor will begin processing each layer of the room. Before it will render the rooms data into a red and black image. The files will be output into the “Levels” folder by the editor’s executable. The files ROOMNAME.txt and ROOMNAME_1.png are the exported version of your room, for use by Rain Worlds engine. Lets get to seeing our room in game! == Setting Up a Mod == In order to get the room into the game, we need to set up a new mod first. It's super easy! In Rain World's root directory, navigate to ''RainWorld_Data\StreamingAssets\mods\''. This folder is where all the built-in mods are kept (workshop mods are installed to a different directory.) To create a new mod, all we need to do is create a new folder. I'll call mine "MyRegionMod" but you can call yours whatever you want. The mod will now appear in the Remix menu, so we can enable it. To add details like a description, dependencies, ect. we can add modinfo file as detailed in the [[Downpour Reference/Mod Directories]] page, but for now we'll leave it as a default folder. The StreamingAssets folder is the main directory where the game keeps all its assets. And each mod folder is treated as if its contents are in StreamingAssets, which is how we can modify the game without touching any of its files. The vanilla rooms for SU are kept in ''StreamingAssets\world\su-rooms\'', so we're going to make a parallel folder in our mod, at ''MyRegionMod\world\su-rooms''. Then, we can copy the ROOMNAME.txt and ROOMNAME_1.png files from the editor’s level export folder and past them into our su-rooms folder. Next, we need to actually connect our room to the rest. There is already an easy to use DISCONNECTED entrance in Outskirts, so we will use that as a way to quickly test our room. Navigate to ''StreamingAssets\world\su\'' and open world_su.txt. This is Outskirt's World.txt file. The details of this file are in this article: [[World File Format]]. However, for the purpose of this tutorial, we won't go into the formatting quirks too much, but rather doing what's necessary to get our room in. If we create a new world_su.txt in ''MyRegionMod\world\su\'' then it'll replace the vanilla one - but that's not what we want to do! We only want to modify a small portion of it. We can do this using [[Downpour Reference/Modification Files]]. These are a special format of files that go in a slightly different directory. Instead of ''MyRegionMod\world\su\world_su.txt'' we'll create a new file at ''MyRegionMod\modify\world\su\world_su.txt''. Inside this file we can put the following contents: <syntaxhighlight lang=""> [MERGE] ROOMS SU_A63 : SU_B12, SU_A37, SU_myroom SU_myroom : SU_A63 END ROOMS [ENDMERGE] </syntaxhighlight> This will merge the lines we specified into the ROOMS section of the vanilla world_su.txt. The vanilla file already contains SU_A63 : SU_B12, SU_A37, DISCONNECTED, but the merge operation will automatically replace that line with out new one. We can now start Rain World! If this has all been done correctly. Then you will be able to load your file without it crashing to a grey screen. Simply navigate to SU_A63 to see the freshly added connection! You can peak into the su-rooms folder and find SU_A63_1.png to see what the room looks like to know where it is in game! == Making Mistakes == [[File:rfg-5.png|thumb|none|alt=5|5]] Our first room is pretty rough! Not everything will be perfect of course! This is a time to see if everything in our geometry works right! If pits are impossible to jump across, or if a jump is just a little our of reach. This is the time to tweak our level till we are happy with the layout. Render times are very fast with just a single layer and some walls after all! Don’t be afraid of mistakes at this point. Just fix them and tweak until your room feels like it is playable, and there are no locations that you can become stuck in. Repeat the steps above to edit, re-render, and re-install the room. You will no longer need to link the level to the world again! You only need to update the room files and image. You do not even need to close Rain World to test these changes. Simply dying, and returning to the room is enough to cause the room to reload for you to test the new collisions! == A Start To Detailing == [[File:rfg-6.png|thumb|none|alt=6|6]] This looks like another crazy jump! But once you get used to the materials the editor gives you, the tile editor will become a playground, and you may even start designing your levels with it, and instead use the geometry editor just to compliment your tiles! It will all come to you as your understanding and comfort of the editor increases. The details I’ve applied myself, have been to paint various materials in the same style Outskirts uses. Large metal plates surrounding dense pipes on corners. Concrete as the base material. The rare inclusion of pipes and machines. Along with a few things I enjoy using in my own levels. Such as large signs from the Misc category, and the insides of large pipes! The tile menu can be navigated using WASD keys. Many large tiles have a collision requirement. Holding G while clicking will automatically place the required geometry for you. This allows you to build things like pipes or complex machines without revisiting the geometry editor, or to construct rooms almost entirely out of tiles. However, you will still need to visit the geometry editor at some point for the bulk of your room’s padding. Where you will paint the traditional tile “materials” over solid walls. The colored dots in the picture are walls painted with a specific material. These are applied as the level is rendered! For now we are still just focusing on layer 1! == A Second Render == [[File:rfg-7.png|thumb|none|alt=7|7]] Things are starting to come together now! We can do a second little peak at how the room plays. After all, we’ve likely done some tweaks with our detailing. Something is still missing however. Using only the first layer of Rain World’s rooms can only give us so much detail! This level needs some DEPTH! == Depth, and the Art of Backgrounds == [[File:rfg-8.png|thumb|none|alt=8|8]] Lets head back into the editor! In the geometry editor, use the layer tool in the bottom left to change to layer 2, and paint over the places we want to place a “back wall” to our room! This layer is also one that creatures can climb on. Blue lizards often do this! Some details on the first layer will also “bleed” into layers behind them. This happens most with the insides of pipes and large chimneys! You can see in the screenshot that I have not placed any layer 2 walls behind the pipe segments at the bottom of the room’s vat area. I’ve done this so that the back wall will not cover over the inside of the pipes during the render! Once you are done painting, save, export text, and do a render! Lets do another test of how our level looks! == A Third Render == [[File:rfg-9.png|thumb|none|alt=9|9]] Yet another render, and more to see and tweak! We can fix any mistakes easily as we go. You can also skip each rendering step, and do all the layers at once if you are confident with the editor! I’ll be doing a third layer, and correcting all the issues on layer 2 by the next section. All the info you need is in the official editor’s article here: [[Level Editor]]. There is also a large guide of all tiles and materials, and how they look once rendered here: https://imgur.com/a/Vz3Kk The next steps involve tweaking, rendering, retweaking, and rerendering until you are happy with the base design of your level! Remember, that some creatures use layer 2 to climb on walls, but layer 3 is far enough in the background for nothing to interact with it! Layer 1 is solid to all creatures with few if at all exceptions. Make sure you cannot get trapped in your level! == Effects and You == [[File:rfg-10.png|thumb|none|alt=10|10]] It’s time to start painting! Now that you’ve solved any issues on your tile layers, and painted yourself a background layer. You are now ready to start painting effects! Remember though. Each effect slows down the render of the level quite a bit. From now on it will begin to get more time consuming to fix mistakes in the level! Especially once you start making larger rooms! Effects are what make Rain World rooms look special. They alter, distort, and deform your tiles. Grow plants, and even alter tiles entirely! The effects editor has an example image of every effect, and its basic usage outline in this article: [[Level Editor#Editors|Effects Editor]]. For the basics though! BlackGoo and Slime; These two effects are used in nearly every screen in Rain World to some degree! Slime makes every tile look slightly drippy and goopy. Like a mess has been rubbed onto them. BlackGoo forms the outer “shadow” of rooms. Both of these work together to make your room look less repetitive and clean! == Yet another rendering == [[File:rfg-11.png|thumb|none|alt=11|11]] Look how far we’ve come! From an empty screen with nothing. To a room that feels like it is simply missing “something” before it is finished! Things like the brickwork along the sides passing over the BlackGoo( It only applies itself over certain materials!) can be corrected using large junk or dirt where you would want the BlackGoo down there. You can also apply other effects till you are happy with the room. This includes everything from rubble, distortions, plants, and even daddy long leg corrupted walls! The only limits is your imagination to making effects work together, and the tiles you have to use! Once you’ve applied the effects you want, and have re-rendered till the level looks right. Next up is to add some props to our room! == Fancy Props and Design == [[File:rfg-12.png|thumb|none|alt=12|12]] Remember to always save and keep backups! Some editor tabs can be more fussy then others! Props are used to detail your room even further. Allowing you to place details without the grid, and at any angle and distorted shape you want! The control are outlined in the article here: [[Level Editor#Editors|Prop Editor]]. While this is not too complex of a section. Adding a few proper can help break the rather straight geometry normally present in Rain World’s levels by giving them some more curved shapes to look at. Such as tubes and valves between containers or machines! Once you are all setup, we can render and move onto using the dev tools to configure the rooms more fine details! Remember. You can always re-render and re-export a level as many times as you need. At no point does a level become impossible to edit. With the one exception of losing its project save file! == Dev tool configurations == [[File:rfg-13.png|thumb|none|alt=13|13]] We can now move onto using the [[Dev Tools]] to configure the level’s more detailed settings! Everything from the room’s colors, effects, and even how the rain timer affects this room! Want a section of outskirts with some kind of lightning machine? Go ahead! Want to make a flooding cave system? It’s all in here! The room’s palette is not tied to the region. However most regions have “templates” that you can use to automatically set room settings to. Instead of needing to do each room one by one the same way. You can change anything you need to away from the template default, or click “NONE” beneath in the template section to use purely your own settings. The rooms palette can also be configured to fade between it, and another palette. Allowing you to configure the exact colors you would need. The various effects can also be configured to use Color1 or Color2 of the effect palettes. These are used to set the colors of plants. Giant signs, and even daddy long leg corruption! Exploring the dev tools documentation will give you far more info and ideas then me directly telling you every possible situation. Remember that some objects and room settings require a reload of the room to appear! Don’t forget to add sounds and some environmental ambience to flesh out your room, to make it feel like a unique location in this world! ''A very IMPORTANT notice! Be sure to click the save button before you reload the room'' somehow! Or your changes will be lost! All of these configurations are save to ROOMNAME_settings.txt. == Over and Over Again == [[File:rfg-14.png|thumb|none|alt=14|14]] The process of making a full region is filled with this! Making rooms from the ground up, detailing and configuring them, before linking another room onto the chain. The only real difference is that you are doing so from the gates of your own region, instead of a small room connected to the side of outskirts! There are already a few pages of documentation related to connecting in a new region yourself! The main one can be found here: [[Adding-A-New-Region.html|Adding new Regions]]. The details of how to setup creatures and connections for the region are here: [[World File Format]]. Finally, the dev tool’s map editor for making your region properly show as a map in game is here: [[Dev_Tools#Interface_Tabs#Map-0|Map Tab]]. I’ll likely be expanding this guide at some point in the future, but for now this is the basics of how to create a room from scratch! Look through the other articles for things like: Raising the water level, setting up creature spawns, understanding doors, adding food, placing objects and plants, adding sounds and effects, specific room triggers, and the various special room settings! And remember! Have fun! == Why Do My Rooms Crash? == There are multiple reasons Rain World will dislike your rooms or connections. These are a few common, and more niche reasons why the game may be crashing. === Doors outside of room bounds: === ALWAYS place every part of a short cut’s path inside the room’s boundary. Any short cut paths outside of it are ignored and will break the game when loaded. Crashing to a grey screen on file load. === Accidental Doors and Dens: === The editor is a strange tool. It also has a second cursor in geometry mode… for some reason. An accidental key press may have placed a den, short cut entrance, or other kind of door in the room without proper connections. Take a peak over your room for any issues. === Incorrect Region Prefix: === the prefix at the start of a room file should match the region you are placing it inside. For this guide we focus on tests rooms inside of outskirts ( SU_ ). If you are bringing these rooms to a custom region by renaming them, be sure to open the room’s data file, and edit the first line to match the renamed version of the file. [[Category:Content Mods]] 0851c971510183369bcfa205ccdb0b0d957d6064 Custom Regions Support 0 101 505 444 2023-06-09T21:04:44Z Heeymiata 191 Changed page body to match current state of development for the CRS 1.9 port. wikitext text/x-wiki {{Toolinfo |name=Custom Regions Support |type=Core dependency mod |authors=Garrakx, Slime_Cubed, Henpemaz |maintainers=Garrakx |status=Supported |releases=[https://github.com/Garrakx/Custom-Regions GitHub] }} {{Cleanup}} {{Legacy}} '''Custom Regions Support''' or '''CRS''' is a library/util mod that was created as an easier way to install [[Content Mods]], replacing file merging. It allows to install multiple region mods at once easily, quickly toggle them, and makes region development less messy. '''Custom Regions Support is currently in beta for Rain World 1.9.''' As of now, it is the primary way of installing any and all custom regions, and many of them are ''CRS-exclusive''. == Features == === Runtime worldfile merging === ''For basics of region architecture, see [[World File Format]]'' CRS attempts to smartly combine region world files and avoid room connectivity conflicts. It is the most effective if region mods don't distribute full modified copies of WORLD_XX.txt files for conflict-prone connection (such as vanilla region's WORLD_XX, when a modded region connects to it), and instead ''only include lines that need to be changed or added''. This is commonly referred to as "refining worldfiles". In addition to connection files, it can also merge region property files. === In-game downloader === CRS config menu allows the user to install most region packs from inside the game in one click, including their dependency DLLs, and also quickly toggle installed packs on and off. Downloader menu is reshuffled every day to give every CRS-published region a shot. === Region-conditional connections === Connections may be toggled depending on if a certain region is present: <pre> ROOMS (TM, !BL)roomA : roomB, roomD //only used if TM is installed and BL is not ENDROOMS </pre> This can be combined with unused vanilla behaviour of character-specific connections. === Connection fixer === Starting with v0.9.xx, CRS can attempt to fix some broken connections. This behaviour isn't a catchall but can make some conflicts less lethal. === Additional asset loading === CRS allows easily loading assets commonly bundled with most regions, such as music files, region splash art for passage/regions map screens, decals etc. === Misc === * Making previously hardcoded settings (electric gates, albino colouring on creatures, chance of salamander colouring etc) configurable with json files * Removing creature spawns * No-code addition of custom pearls * Adding unlockable arenas f54b3369c6860e49f49d690782750ef44a1f7c9d Properties File 0 199 509 2023-06-20T04:08:38Z Bro748 31 New Page wikitext text/x-wiki The Properties file is one that can assign various general settings for each region. It is not required for a region to function, but is often desired. == General Setup == A region's Properties file is placed at <code>World\XX\Properties.txt</code> Slugcat-specific properties can be created by appending the slugname separated by a <code>-</code> ie, <code>World\XX\Properties-Slugname.txt</code> '''Due to a bug,''' half the time the properties file is read it expects a space before the slugname. It's recommended when necessary to duplicate the file with both expected names. <code>World\XX\Properties-Slugname.txt</code> & <code>World\XX\Properties- Slugname.txt</code> This file follows a 'key: value' format. Every line of the file will begin with the name of the property it is assigning (the 'key'), followed by the value to assign (the 'value') with the two being split by <code>: </code> (colon + space) <code>PropertyName: value</code> <- this would be a valid format for a property line Some properties will be numbers, others may be strings, others may follow more specific formats. Any line that does not follow this format will not be read, so more info can be written in the file without anything breaking. == Properties == Most properties use one of the following formats for their values: An integer in this case refers to any whole number equal to or greater than 0 <code>PropertyName: 5</code> A float in this case refers to a floating point value between 0.0 and 1.0, usually acting as a percentage <code>PropertyName: 0.8</code> A boolean is either 'true' or 'false' represented by '1' or '0' respectively <code>PropertyName: 1</code> A color is three floats separated by <code>, </code> (comma + space) in RGB order <code>PropertyName: 0.5, 0.8, 0.5</code> <- a very desaturated green Below is a table of most recognized properties. Names are case sensitive, and if the property isn't specified, the default will be used instead. {|class="wikitable" |- !| '''Name''' !| '''Value Format''' !| '''Default''' !| '''Description''' |- | batDepleteCyclesMin || integer || 2 || The fewest cycles a swarm room in the region will remain inactive |- | batDepleteCyclesMax || integer || 7 || The most cycles a swarm room in the region will remain inactive |- | batDepleteCyclesMaxIfLessThanFiveLeft || integer || 4 || Overrides the above if less than 5 swarm rooms are active in the region |- | batDepleteCyclesMaxIfLessThanTwoLeft || integer || 3 || Overrides the above if less than 2 swarm rooms are active in the region |- | batsPerActiveSwarmRoom || integer || 10 || Number of batflies that spawn in an active swarm room |- | batsPerInactiveSwarmRoom || integer || 4 || Number of extra batflies to spawn in random active swarm rooms for each inactive |- | overseersSpawnChance || float || 0.8 || The chance that blue overseers will spawn in the region |- | overseersMin || integer || 1 || Minimum amount of blue overseers that can spawn when the spawn chance return true |- | overseersMax || integer || 3 || Same as above, but maximum |- | playerGuideOverseerSpawnChance || integer || 1 || The chance that the player guide overseer will spawn in the region |- | scavengerDelayInitialMin || integer || 900 || Minimum number of ticks the first player kill squad will wait before chasing the player* |- | scavengerDelayInitialMax || integer || 1100 || Same as above, but maximum* |- | scavengerDelayRepeatMin || integer || 4100 || Minimum number of ticks any subsequent player kill squad will wait* |- | scavengerDelayRepeatMax || integer || 08200 || Same as above, but maximum* |- | scavsMin || integer || 0 || UNUSED |- | scavsMax || integer || 5 || UNUSED |- | scavsSpawnChance || integer || 0.3|| UNUSED |- | corruptionEffectColor || color || 0.0, 0.0, 1.0 || Main color for proto rot, and some Longlegs creatures** |- | corruptionEyeColor || color || 0.0, 0.0, 1.0 || Same as above, but eye color** |- | kelpColor || color || 1.0, 0.0, 0.1 || Color for kelp in the region |- | blackSalamanderChance || float || 0.34 || Chance a salamander will be black |- | albinos || boolean || false || If true, turns leviathans and jetfish albino |- | slugPupSpawnChance || float || 0 || Chance that a slugpup will spawn in the region |- | glacialWasteland || boolean || false || Increases the fierceness of the blizzard effect |- | earlyCycleChance || float || 0.02 || Chance of a precycle occurring |- | earlyCycleFloodChance || float || 0.33 || Chance of the precycle being flooded |- |} (*scavengerDelay values only apply if ScavengerKillSquadDelay is turned on in Remix) (*Daddy Longlegs and Terror Longlegs are almost always affected by properties colors, but Brother Longlegs colors are only affected if the player is Artificer or Spearmaster) The following properties are more complicated and require more complex elaboration. <code>Subregions</code> The name of a subregion, including the region's name itself. Rooms can then be assigned specific subregion names through the [[Dev_Tools#Map-0|devtools map page]] to make region bumps occur. Each subregion should be listed as a different line. Ie, <syntaxhighlight lang=""> Subregion: Subterranean Subregion: Depths Subregion: Filtration System </syntaxhighlight> <code>Room Settings Templates</code> The names of all room settings templates for the region. Each room settings template name should be listed on the same line, separated by <code>, </code> (comma + space,) with the first one acting as the default. Ie, <syntaxhighlight lang=""> Room Setting Templates: Subway, Filter, Temple </syntaxhighlight> (The actual room settings files go in World\XX\ and follow a name format of XX_SettingsTemplate_Name.txt with 'Name' being what's listed in the properties file.) <code>Room_Attr</code> The room attractiveness settings for a specific room. Each room's attractiveness should be listed on different lines. After the room name, another <code>: </code> (colon + space) follows, which is then proceeded by creature names paired by a <code>-</code> to their attraction type for the room, with different creatures being separated by <code>,</code> (comma.) Ie, <syntaxhighlight lang=""> Room_Attr: SB_F03: RedCentipede-Forbidden,Overseer-Stay,BigSpider-Avoid,SpitterSpider-Avoid, Room_Attr: SB_H03: RedCentipede-Forbidden,DropBug-Like, Room_Attr: SB_E04: RedCentipede-Avoid,Overseer-Forbidden,BigSpider-Like,SpitterSpider-Like,DropBug-Stay, </syntaxhighlight> '''It is not recommended to write room attractions by hand!''' These can automatically be assigned through the [[Dev_Tools#Map-0|devtools map page]] UI, or through external tools like the [https://www.youtube.com/watch?v=MgeEBM9EKS4 World Editor.] == Examples == Here is an example of a Properties file with all the default values <syntaxhighlight lang=""> batDepleteCyclesMin: 2 batDepleteCyclesMax: 7 batDepleteCyclesMaxILessThanTwoLet: 3 batDepleteCyclesMaxILessThaniveLet: 4 batsPerActiveSwarmRoom: 10 batsPerInactiveSwarmRoom: 4 overseersSpawnChance: 0.8 overseersMin: 1 overseersMax: 3 playerGuideOverseerSpawnChance: 1 scavengerDelayInitialMin: 900 scavengerDelayInitialMax: 1100 scavengerDelayRepeatMin: 4100 scavengerDelayRepeatMax: 8200 scavsMin: 0 scavsMax: 5 scavsSpawnChance: 0.3 corruptionEectColor: 0.0, 0.0, 1.0 corruptionEyeColor: 0.0, 0.0, 1.0 kelpColor: 1.0, 0.0, 1.0 albinos: 0 blackSalamanderChance: 0.34 slugPupSpawnChance: 0 glacialWasteland: 0 earlyCycleChance: 0.02 earlyCycleloodChance: 0.33 //the following values are not defaults as no defaults for these exist Room Setting Templates: Inside, Outside Subregion: My Region Subregion: My Subregion //please don't write Room_Attr by hand </syntaxhighlight> But the best examples are the ones already in the game. A good way to become more familiar with these properties is to look at vanilla files. 025ea0021c76826febe44bc5d437124ae07e50c5 510 509 2023-06-20T16:41:10Z Bro748 31 Add to Category wikitext text/x-wiki The Properties file is one that can assign various general settings for each region. It is not required for a region to function, but is often desired. == General Setup == A region's Properties file is placed at <code>World\XX\Properties.txt</code> Slugcat-specific properties can be created by appending the slugname separated by a <code>-</code> ie, <code>World\XX\Properties-Slugname.txt</code> '''Due to a bug,''' half the time the properties file is read it expects a space before the slugname. It's recommended when necessary to duplicate the file with both expected names. <code>World\XX\Properties-Slugname.txt</code> & <code>World\XX\Properties- Slugname.txt</code> This file follows a 'key: value' format. Every line of the file will begin with the name of the property it is assigning (the 'key'), followed by the value to assign (the 'value') with the two being split by <code>: </code> (colon + space) <code>PropertyName: value</code> <- this would be a valid format for a property line Some properties will be numbers, others may be strings, others may follow more specific formats. Any line that does not follow this format will not be read, so more info can be written in the file without anything breaking. == Properties == Most properties use one of the following formats for their values: An integer in this case refers to any whole number equal to or greater than 0 <code>PropertyName: 5</code> A float in this case refers to a floating point value between 0.0 and 1.0, usually acting as a percentage <code>PropertyName: 0.8</code> A boolean is either 'true' or 'false' represented by '1' or '0' respectively <code>PropertyName: 1</code> A color is three floats separated by <code>, </code> (comma + space) in RGB order <code>PropertyName: 0.5, 0.8, 0.5</code> <- a very desaturated green Below is a table of most recognized properties. Names are case sensitive, and if the property isn't specified, the default will be used instead. {|class="wikitable" |- !| '''Name''' !| '''Value Format''' !| '''Default''' !| '''Description''' |- | batDepleteCyclesMin || integer || 2 || The fewest cycles a swarm room in the region will remain inactive |- | batDepleteCyclesMax || integer || 7 || The most cycles a swarm room in the region will remain inactive |- | batDepleteCyclesMaxIfLessThanFiveLeft || integer || 4 || Overrides the above if less than 5 swarm rooms are active in the region |- | batDepleteCyclesMaxIfLessThanTwoLeft || integer || 3 || Overrides the above if less than 2 swarm rooms are active in the region |- | batsPerActiveSwarmRoom || integer || 10 || Number of batflies that spawn in an active swarm room |- | batsPerInactiveSwarmRoom || integer || 4 || Number of extra batflies to spawn in random active swarm rooms for each inactive |- | overseersSpawnChance || float || 0.8 || The chance that blue overseers will spawn in the region |- | overseersMin || integer || 1 || Minimum amount of blue overseers that can spawn when the spawn chance return true |- | overseersMax || integer || 3 || Same as above, but maximum |- | playerGuideOverseerSpawnChance || integer || 1 || The chance that the player guide overseer will spawn in the region |- | scavengerDelayInitialMin || integer || 900 || Minimum number of ticks the first player kill squad will wait before chasing the player* |- | scavengerDelayInitialMax || integer || 1100 || Same as above, but maximum* |- | scavengerDelayRepeatMin || integer || 4100 || Minimum number of ticks any subsequent player kill squad will wait* |- | scavengerDelayRepeatMax || integer || 08200 || Same as above, but maximum* |- | scavsMin || integer || 0 || UNUSED |- | scavsMax || integer || 5 || UNUSED |- | scavsSpawnChance || integer || 0.3|| UNUSED |- | corruptionEffectColor || color || 0.0, 0.0, 1.0 || Main color for proto rot, and some Longlegs creatures** |- | corruptionEyeColor || color || 0.0, 0.0, 1.0 || Same as above, but eye color** |- | kelpColor || color || 1.0, 0.0, 0.1 || Color for kelp in the region |- | blackSalamanderChance || float || 0.34 || Chance a salamander will be black |- | albinos || boolean || false || If true, turns leviathans and jetfish albino |- | slugPupSpawnChance || float || 0 || Chance that a slugpup will spawn in the region |- | glacialWasteland || boolean || false || Increases the fierceness of the blizzard effect |- | earlyCycleChance || float || 0.02 || Chance of a precycle occurring |- | earlyCycleFloodChance || float || 0.33 || Chance of the precycle being flooded |- |} (*scavengerDelay values only apply if ScavengerKillSquadDelay is turned on in Remix) (*Daddy Longlegs and Terror Longlegs are almost always affected by properties colors, but Brother Longlegs colors are only affected if the player is Artificer or Spearmaster) The following properties are more complicated and require more complex elaboration. <code>Subregions</code> The name of a subregion, including the region's name itself. Rooms can then be assigned specific subregion names through the [[Dev_Tools#Map-0|devtools map page]] to make region bumps occur. Each subregion should be listed as a different line. Ie, <syntaxhighlight lang=""> Subregion: Subterranean Subregion: Depths Subregion: Filtration System </syntaxhighlight> <code>Room Settings Templates</code> The names of all room settings templates for the region. Each room settings template name should be listed on the same line, separated by <code>, </code> (comma + space,) with the first one acting as the default. Ie, <syntaxhighlight lang=""> Room Setting Templates: Subway, Filter, Temple </syntaxhighlight> (The actual room settings files go in World\XX\ and follow a name format of XX_SettingsTemplate_Name.txt with 'Name' being what's listed in the properties file.) <code>Room_Attr</code> The room attractiveness settings for a specific room. Each room's attractiveness should be listed on different lines. After the room name, another <code>: </code> (colon + space) follows, which is then proceeded by creature names paired by a <code>-</code> to their attraction type for the room, with different creatures being separated by <code>,</code> (comma.) Ie, <syntaxhighlight lang=""> Room_Attr: SB_F03: RedCentipede-Forbidden,Overseer-Stay,BigSpider-Avoid,SpitterSpider-Avoid, Room_Attr: SB_H03: RedCentipede-Forbidden,DropBug-Like, Room_Attr: SB_E04: RedCentipede-Avoid,Overseer-Forbidden,BigSpider-Like,SpitterSpider-Like,DropBug-Stay, </syntaxhighlight> '''It is not recommended to write room attractions by hand!''' These can automatically be assigned through the [[Dev_Tools#Map-0|devtools map page]] UI, or through external tools like the [https://www.youtube.com/watch?v=MgeEBM9EKS4 World Editor.] == Examples == Here is an example of a Properties file with all the default values <syntaxhighlight lang=""> batDepleteCyclesMin: 2 batDepleteCyclesMax: 7 batDepleteCyclesMaxILessThanTwoLet: 3 batDepleteCyclesMaxILessThaniveLet: 4 batsPerActiveSwarmRoom: 10 batsPerInactiveSwarmRoom: 4 overseersSpawnChance: 0.8 overseersMin: 1 overseersMax: 3 playerGuideOverseerSpawnChance: 1 scavengerDelayInitialMin: 900 scavengerDelayInitialMax: 1100 scavengerDelayRepeatMin: 4100 scavengerDelayRepeatMax: 8200 scavsMin: 0 scavsMax: 5 scavsSpawnChance: 0.3 corruptionEectColor: 0.0, 0.0, 1.0 corruptionEyeColor: 0.0, 0.0, 1.0 kelpColor: 1.0, 0.0, 1.0 albinos: 0 blackSalamanderChance: 0.34 slugPupSpawnChance: 0 glacialWasteland: 0 earlyCycleChance: 0.02 earlyCycleloodChance: 0.33 //the following values are not defaults as no defaults for these exist Room Setting Templates: Inside, Outside Subregion: My Region Subregion: My Subregion //please don't write Room_Attr by hand </syntaxhighlight> But the best examples are the ones already in the game. A good way to become more familiar with these properties is to look at vanilla files. [[Category:Content Mods]] 29ac8a1700ab9ae2bc4382c5c2511bc424dbc7d0 Creating A Region 0 200 511 2023-06-20T21:10:00Z Bro748 31 Created page with "Before reading this page, it's expected you know how to [[Downpour_Reference/Mod_Directories|set up a new mod.]] Every filepath used will be relative to RainWorld_Data\StreamingAssets, or to the first mod that contains the file. All file names and folder names are case insensitive. == Regions.txt == Every region has a 2 letter "acronym" or "id". This acronym must be unique to the region, otherwise a variety of stuff will break. This also is the biggest source of incom..." wikitext text/x-wiki Before reading this page, it's expected you know how to [[Downpour_Reference/Mod_Directories|set up a new mod.]] Every filepath used will be relative to RainWorld_Data\StreamingAssets, or to the first mod that contains the file. All file names and folder names are case insensitive. == Regions.txt == Every region has a 2 letter "acronym" or "id". This acronym must be unique to the region, otherwise a variety of stuff will break. This also is the biggest source of incompatibilities between multiple mods, so modders have created a [https://docs.google.com/spreadsheets/d/14wt42_ZalI5di8zpUFx3WvPWldC_L7SwIbgb_TxOpUk/edit#gid=634960091 lease for reserving acronyms.] (Don't add an entry to the region lease until you've made a couple rooms and know you are serious about finishing the region!) The game gets the list of region acronyms to load from World\Regions.txt Vanilla's Regions.txt looks like this <syntaxhighlight lang=""> CC DS HI GW SI SU SH SL LF UW SB SS </syntaxhighlight> Adding a new acronym to this file will tell the game to load that acronym's region. Modifying the file directly should be avoided, instead it should be modified using a [[Downpour_Reference/Modification_Files|modification file.]] So to add a new acronym, the following is what typically should be done. <code>MyMod\Modify\World\Regions.txt</code> <syntaxhighlight lang=""> [MERGE] XX [ENDMERGE] </syntaxhighlight> (some mods use [ADD] instead of [MERGE] which under normal circumstances is functionally the same, but [MERGE] prevents duplicates so it is generally safer.) Once this region is added, the game will now look for the new XX region! However, it will crash on startup if no World File exists for the region... == World_XX.txt == The World File is the only required file for a region to work. The full path will be World\XX\World_XX.txt The World File defines how rooms connect, what creatures spawn, what room changes to make for each slugcat, and various other things. Due to how big of a file it is, it has its own page, which should be referred to instead of this one for any world file formatting. [[World_File_Format]] For some general things about getting a region working, the only parts of a world file needed to work are the ROOMS and CREATURES section. As such, the most basic world file will look like as follows. <code>MyMod\World\XX\World_XX.txt</code> <syntaxhighlight lang=""> ROOMS END ROOMS CREATURES END CREATURES </syntaxhighlight> Now the region can be loaded by the game, but trying to visit it will crash since there are no rooms! To add rooms, refer to the [[World_File_Format]] page for the syntax, and the next section for where to put the room files. == Room Folders == The World\XX-Rooms\ folder is where all non-gate room files should go. Rooms are made in the [[level_editor]], and then after [[Level_Editor#Rendering|Rendering]], the output files can be copied into the World\XX-Rooms\ folder. Every room in this folder must be prefixed by the region's acronym and an underscore or else the game will not be able to find its location. <code>MyMod\World\XX-Rooms\XX_MYROOM.txt</code> <- this is a valid path to a room <code>MyMod\World\XX-Rooms\MYROOM.txt</code> <- this is an invalid filepath <code>MyMod\World\XX_Rooms\XX_MYROOM.txt</code> <- this is also an invalid filepath Gate room files will go in World\Gates\ instead. Gate rooms should be named with the format of GATE_XX_YY. If they don't start with GATE_ the game will not be able to find the room file in the Gates folder, and if it doesn't include both acronyms for the regions it is between then it will not know what region to load. <code>MyMod\World\Gates\GATE_XX_YY.txt</code> <- this is a valid path to a gate <code>MyMod\World\Gates\XX_YY.txt</code> <- this is an invalid path to a gate <code>MyMod\World\XX-Rooms\GATE_XX_YY.txt</code> <- this is an invalid path to a gate <code>MyMod\World\XX-Rooms\XX_XX_YY.txt</code> <- this will technically load and function properly, but it is not recommended If a room file isn't found in either of those two folders, the game will, as a last resort, look in World\Gates\Gate Shelters\ and then Levels\ So technically all rooms could be placed in either of these folders and can be loaded by any region. Any room in the Levels folder will appear in the Arena select menu, so it's a good palce to put rooms to be able to quickly test them, but the rooms should not be left there when the mod is finished. <code>MyMod\World\Gates\Gate Shelters\GATE2_XX_YY.txt</code> <- allows a 3rd gate between two regions <code>MyMod\Levels\MYROOM.txt</code> <-this room can be put in the region and will show up in arena Once you've added your region to Regions.txt, created a world file, and added a room, you can now visit your region! But there are still some region related files and settings you may want to use. == DisplayName.txt == World\XX\DisplayName.txt contains a single line that contains the name of the region, as it should be displayed in the main menu. Display name files can also be provided that are suffixed by a slugcat name to change the name of the region for specific slugcat campaigns. (ie: <code>DisplayName-Red.txt</code>) == Properties.txt == Every region may have a Properties file to set various properties, such as swarm room deplete settings, monster kelp color, subregions, and more. Since there are many many options for the Properties file, it has its own page that should be deferred to. [[Properties_File]] == Map Files == Most regions will have the following files: - World\XX\Map_XX.txt - World\XX\Map_XX.png - World\XX\Map_Image_XX.txt These files will be automatically generated when saving or rendering the map on the devtools map page, however if the files don't exist already, the game will try to save them to a non-existent vanilla directory. So you may have to create empty versions of the files in order to generate them the first time. Map files can be suffixed by a slugcat name to make a map render exclusive to a specific slugcat campaign. (ie: <code>map_xx-red.png</code>) While it is generally not recommended to manually modify the files, there might be situations where it's necessary, so we'll go over the formatting for each file. <big>Map_XX.txt</big> There are two types of lines - room lines & connection lines --room lines format--- Each room in the region will have its own line to set all of the data. The positions here are generated with 0,0 being the average of all rooms. However, they are actually positioned relative to the bottom left room. ROOMNAME: CanonPosX><CanonPosY><DevPosX><DevPosY><Layer><SubregionName><RoomWidth><RoomHeight example <code>SU_B13: 329.0976><334.8371><202.3116><567.9238><1><Outskirts><48><78</code> --connection lines format-- Each connection between two rooms will have a unique line, specifying the position of the entrance in each room and direction the entrance starts in. Connection: Roomname1,Roomname2,RoomPos1X,RoomPos1Y,Room2PosX,Room2PosY,Room1Direction,Room2Direction example <code>Connection: SU_B13,SU_A33,15,16,14,34,3,1</code> <big>Map_XX.png</big> The map png determines what to draw on the in-game hud map. Each pixel represents a different type. * Green (#00FF00): don't draw anything * Black (#000000): draw solid wall * Red (#FF0000): draw sky * Darker Red (990000): draw poles or slopes depending on context * Purple (#FF00FF): draw water * Darker Purple (#9900FF): draw underwater poles or slopes depending on context <big>Map_Image_XX.png</big> This file has the positions of the rooms on the png itself. This file is only read by the modloader, in an attempt to parse together multiple maps for the same region (although this currently does not work properly.) ROOMNAME: PosX,PosY,RoomWidth,RoomHeight example <code>SU_B13: 744,1118,48,78</code> [[Category:Content Mods]] 3330523682d3917ea7bda849f1640fedc37622e2 512 511 2023-06-20T21:11:36Z Bro748 31 wikitext text/x-wiki Before reading this page, it's expected you know how to [[Downpour_Reference/Mod_Directories|set up a new mod.]] Every filepath used will be relative to RainWorld_Data\StreamingAssets, or to the first mod that contains the file. All file names and folder names are case insensitive. == Regions.txt == Every region has a 2 letter "acronym" or "id". This acronym must be unique to the region, otherwise a variety of stuff will break. This also is the biggest source of incompatibilities between multiple mods, so modders have created a [https://docs.google.com/spreadsheets/d/14wt42_ZalI5di8zpUFx3WvPWldC_L7SwIbgb_TxOpUk/edit#gid=634960091 lease for reserving acronyms.] (Don't add an entry to the region lease until you've made a couple rooms and know you are serious about finishing the region!) The game gets the list of region acronyms to load from World\Regions.txt Vanilla's Regions.txt looks like this <syntaxhighlight lang=""> CC DS HI GW SI SU SH SL LF UW SB SS </syntaxhighlight> Adding a new acronym to this file will tell the game to load that acronym's region. Modifying the file directly should be avoided, instead it should be modified using a [[Downpour_Reference/Modification_Files|modification file.]] So to add a new acronym, the following is what typically should be done. <code>MyMod\Modify\World\Regions.txt</code> <syntaxhighlight lang=""> [MERGE] XX [ENDMERGE] </syntaxhighlight> (some mods use [ADD] instead of [MERGE] which under normal circumstances is functionally the same, but [MERGE] prevents duplicates so it is generally safer.) Once this region is added, the game will now look for the new XX region! However, it will crash on startup if no World File exists for the region... == World_XX.txt == The World File is the only required file for a region to work. The full path will be World\XX\World_XX.txt The World File defines how rooms connect, what creatures spawn, what room changes to make for each slugcat, and various other things. Due to how big of a file it is, it has its own page, which should be referred to instead of this one for any world file formatting. [[World_File_Format]] For some general things about getting a region working, the only parts of a world file needed to work are the ROOMS and CREATURES section. As such, the most basic world file will look like as follows. <code>MyMod\World\XX\World_XX.txt</code> <syntaxhighlight lang=""> ROOMS END ROOMS CREATURES END CREATURES </syntaxhighlight> Now the region can be loaded by the game, but trying to visit it will crash since there are no rooms! To add rooms, refer to the [[World_File_Format]] page for the syntax, and the next section for where to put the room files. == Room Folders == The World\XX-Rooms\ folder is where all non-gate room files should go. Rooms are made in the [[Level_Editor]], and then after [[Level_Editor#Rendering|Rendering]], the output files can be copied into the World\XX-Rooms\ folder. Every room in this folder must be prefixed by the region's acronym and an underscore or else the game will not be able to find its location. <code>MyMod\World\XX-Rooms\XX_MYROOM.txt</code> <- this is a valid path to a room <code>MyMod\World\XX-Rooms\MYROOM.txt</code> <- this is an invalid filepath <code>MyMod\World\XX_Rooms\XX_MYROOM.txt</code> <- this is also an invalid filepath Gate room files will go in World\Gates\ instead. Gate rooms should be named with the format of GATE_XX_YY. If they don't start with GATE_ the game will not be able to find the room file in the Gates folder, and if it doesn't include both acronyms for the regions it is between then it will not know what region to load. <code>MyMod\World\Gates\GATE_XX_YY.txt</code> <- this is a valid path to a gate <code>MyMod\World\Gates\XX_YY.txt</code> <- this is an invalid path to a gate <code>MyMod\World\XX-Rooms\GATE_XX_YY.txt</code> <- this is an invalid path to a gate <code>MyMod\World\XX-Rooms\XX_XX_YY.txt</code> <- this will technically load and function properly, but it is not recommended If a room file isn't found in either of those two folders, the game will, as a last resort, look in World\Gates\Gate Shelters\ and then Levels\ So technically all rooms could be placed in either of these folders and can be loaded by any region. Any room in the Levels folder will appear in the Arena select menu, so it's a good palce to put rooms to be able to quickly test them, but the rooms should not be left there when the mod is finished. <code>MyMod\World\Gates\Gate Shelters\GATE2_XX_YY.txt</code> <- allows a 3rd gate between two regions <code>MyMod\Levels\MYROOM.txt</code> <-this room can be put in the region and will show up in arena Once you've added your region to Regions.txt, created a world file, and added a room, you can now visit your region! But there are still some region related files and settings you may want to use. == DisplayName.txt == World\XX\DisplayName.txt contains a single line that contains the name of the region, as it should be displayed in the main menu. Display name files can also be provided that are suffixed by a slugcat name to change the name of the region for specific slugcat campaigns. (ie: <code>DisplayName-Red.txt</code>) == Properties.txt == Every region may have a Properties file to set various properties, such as swarm room deplete settings, monster kelp color, subregions, and more. Since there are many many options for the Properties file, it has its own page that should be deferred to. [[Properties_File]] == Map Files == Most regions will have the following files: - World\XX\Map_XX.txt - World\XX\Map_XX.png - World\XX\Map_Image_XX.txt These files will be automatically generated when saving or rendering the map on the devtools map page, however if the files don't exist already, the game will try to save them to a non-existent vanilla directory. So you may have to create empty versions of the files in order to generate them the first time. Map files can be suffixed by a slugcat name to make a map render exclusive to a specific slugcat campaign. (ie: <code>map_xx-red.png</code>) While it is generally not recommended to manually modify the files, there might be situations where it's necessary, so we'll go over the formatting for each file. <big>Map_XX.txt</big> There are two types of lines - room lines & connection lines --room lines format--- Each room in the region will have its own line to set all of the data. The positions here are generated with 0,0 being the average of all rooms. However, they are actually positioned relative to the bottom left room. ROOMNAME: CanonPosX><CanonPosY><DevPosX><DevPosY><Layer><SubregionName><RoomWidth><RoomHeight example <code>SU_B13: 329.0976><334.8371><202.3116><567.9238><1><Outskirts><48><78</code> --connection lines format-- Each connection between two rooms will have a unique line, specifying the position of the entrance in each room and direction the entrance starts in. Connection: Roomname1,Roomname2,RoomPos1X,RoomPos1Y,Room2PosX,Room2PosY,Room1Direction,Room2Direction example <code>Connection: SU_B13,SU_A33,15,16,14,34,3,1</code> <big>Map_XX.png</big> The map png determines what to draw on the in-game hud map. Each pixel represents a different type. * Green (#00FF00): don't draw anything * Black (#000000): draw solid wall * Red (#FF0000): draw sky * Darker Red (990000): draw poles or slopes depending on context * Purple (#FF00FF): draw water * Darker Purple (#9900FF): draw underwater poles or slopes depending on context <big>Map_Image_XX.png</big> This file has the positions of the rooms on the png itself. This file is only read by the modloader, in an attempt to parse together multiple maps for the same region (although this currently does not work properly.) ROOMNAME: PosX,PosY,RoomWidth,RoomHeight example <code>SU_B13: 744,1118,48,78</code> [[Category:Content Mods]] 9a904023e7948972d6bfbb5f77cb44e0045a5c28 513 512 2023-06-20T21:13:35Z Bro748 31 wikitext text/x-wiki Before reading this page, it's expected you know how to [[Downpour_Reference/Mod_Directories|set up a new mod.]] Every filepath used will be relative to RainWorld_Data\StreamingAssets, or to the first mod that contains the file. All file names and folder names are case insensitive. == Regions.txt == Every region has a 2 letter "acronym" or "id". This acronym must be unique to the region, otherwise a variety of stuff will break. This also is the biggest source of incompatibilities between multiple mods, so modders have created a [https://docs.google.com/spreadsheets/d/14wt42_ZalI5di8zpUFx3WvPWldC_L7SwIbgb_TxOpUk/edit#gid=634960091 lease for reserving acronyms.] (Don't add an entry to the region lease until you've made a couple rooms and know you are serious about finishing the region!) The game gets the list of region acronyms to load from World\Regions.txt Vanilla's Regions.txt looks like this <syntaxhighlight lang=""> CC DS HI GW SI SU SH SL LF UW SB SS </syntaxhighlight> Adding a new acronym to this file will tell the game to load that acronym's region. Modifying the file directly should be avoided, instead it should be modified using a [[Downpour_Reference/Modification_Files|modification file.]] So to add a new acronym, the following is what typically should be done. <code>MyMod\Modify\World\Regions.txt</code> <syntaxhighlight lang=""> [MERGE] XX [ENDMERGE] </syntaxhighlight> (some mods use [ADD] instead of [MERGE] which under normal circumstances is functionally the same, but [MERGE] prevents duplicates so it is generally safer.) Once this region is added, the game will now look for the new XX region! However, it will crash on startup if no World File exists for the region... == World_XX.txt == The World File is the only required file for a region to work. The full path will be World\XX\World_XX.txt The World File defines how rooms connect, what creatures spawn, what room changes to make for each slugcat, and various other things. Due to how big of a file it is, it has its own page, which should be referred to instead of this one for any world file formatting. [[World_File_Format]] For some general things about getting a region working, the only parts of a world file needed to work are the ROOMS and CREATURES section. As such, the most basic world file will look like as follows. <code>MyMod\World\XX\World_XX.txt</code> <syntaxhighlight lang=""> ROOMS END ROOMS CREATURES END CREATURES </syntaxhighlight> Now the region can be loaded by the game, but trying to visit it will crash since there are no rooms! To add rooms, refer to the [[World_File_Format]] page for the syntax, and the next section for where to put the room files. == Room Folders == The World\XX-Rooms\ folder is where all non-gate room files should go. Rooms are made in the [[Level_Editor]], and then after [[Level_Editor#Rendering|Rendering]], the output files can be copied into the World\XX-Rooms\ folder. Every room in this folder must be prefixed by the region's acronym and an underscore or else the game will not be able to find its location. <code>MyMod\World\XX-Rooms\XX_MYROOM.txt</code> <- this is a valid path to a room <code>MyMod\World\XX-Rooms\MYROOM.txt</code> <- this is an invalid filepath <code>MyMod\World\XX_Rooms\XX_MYROOM.txt</code> <- this is also an invalid filepath Gate room files will go in World\Gates\ instead. Gate rooms should be named with the format of GATE_XX_YY. If they don't start with GATE_ the game will not be able to find the room file in the Gates folder, and if it doesn't include both acronyms for the regions it is between then it will not know what region to load. <code>MyMod\World\Gates\GATE_XX_YY.txt</code> <- this is a valid path to a gate <code>MyMod\World\Gates\XX_YY.txt</code> <- this is an invalid path to a gate <code>MyMod\World\XX-Rooms\GATE_XX_YY.txt</code> <- this is an invalid path to a gate <code>MyMod\World\XX-Rooms\XX_XX_YY.txt</code> <- this will technically load and function properly, but it is not recommended If a room file isn't found in either of those two folders, the game will, as a last resort, look in World\Gates\Gate Shelters\ and then Levels\ So technically all rooms could be placed in either of these folders and can be loaded by any region. Any room in the Levels folder will appear in the Arena select menu, so it's a good palce to put rooms to be able to quickly test them, but the rooms should not be left there when the mod is finished. <code>MyMod\World\Gates\Gate Shelters\GATE2_XX_YY.txt</code> <- allows a 3rd gate between two regions <code>MyMod\Levels\MYROOM.txt</code> <-this room can be put in the region and will show up in arena Once you've added your region to Regions.txt, created a world file, and added a room, you can now visit your region! But there are still some region related files and settings you may want to use. == DisplayName.txt == World\XX\DisplayName.txt contains a single line that contains the name of the region, as it should be displayed in the main menu. Display name files can also be provided that are suffixed by a slugcat name to change the name of the region for specific slugcat campaigns. (ie: <code>DisplayName-Red.txt</code>) == Properties.txt == Every region may have a Properties file to set various properties, such as swarm room deplete settings, monster kelp color, subregions, and more. Since there are many many options for the Properties file, it has its own page that should be deferred to. [[Properties_File]] == Map Files == Most regions will have the following files: - World\XX\Map_XX.txt - World\XX\Map_XX.png - World\XX\Map_Image_XX.txt These files will be automatically generated when saving or rendering the map on the devtools map page, however if the files don't exist already, the game will try to save them to a non-existent vanilla directory. So you may have to create empty versions of the files in order to generate them the first time. Map files can be suffixed by a slugcat name to make a map render exclusive to a specific slugcat campaign. (ie: <code>map_xx-red.png</code>) While it is generally not recommended to manually modify the files, there might be situations where it's necessary, so we'll go over the formatting for each file. <big>Map_XX.txt</big> There are two types of lines - room lines & connection lines --room lines format--- Each room in the region will have its own line to set all of the data. The positions here are generated with 0,0 being the average of all rooms. However, they are actually positioned relative to the bottom left room. ROOMNAME: CanonPosX><CanonPosY><DevPosX><DevPosY><Layer><SubregionName><RoomWidth><RoomHeight example <code>SU_B13: 329.0976><334.8371><202.3116><567.9238><1><Outskirts><48><78</code> --connection lines format-- Each connection between two rooms will have a unique line, specifying the position of the entrance in each room and direction the entrance starts in. Connection: Roomname1,Roomname2,RoomPos1X,RoomPos1Y,Room2PosX,Room2PosY,Room1Direction,Room2Direction example <code>Connection: SU_B13,SU_A33,15,16,14,34,3,1</code> <big>Map_XX.png</big> The map png determines what to draw on the in-game hud map. Each pixel represents a different type. * Green (#00FF00): don't draw anything * Black (#000000): draw solid wall * Red (#FF0000): draw sky * Darker Red (990000): draw poles or slopes depending on context * Purple (#FF00FF): draw water * Darker Purple (#9900FF): draw underwater poles or slopes depending on context <big>Map_Image_XX.png</big> This file has the positions of the rooms on the png itself. This file is only read by the modloader, in an attempt to parse together multiple maps for the same region (although this currently does not work properly.) ROOMNAME: PosX,PosY,RoomWidth,RoomHeight example <code>SU_B13: 744,1118,48,78</code> [[Category:Content Mods]] 1b054795e34e1f8fa2c666faa3934ec43be60da9 User:LimitBreaker 2 201 515 2023-06-24T15:30:34Z LimitBreaker 204 create user page wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 Level Editor 0 86 516 514 2023-06-24T15:46:20Z LimitBreaker 204 /* Render Level */ wikitext text/x-wiki {{Cleanup}} == The Official Level Editor == [[File:editorFront.png|400px|thumb|right]] The Level Editor is an application created by the Rain World developers in order to create new in-game rooms and edit existing ones. There are two officially released versions of the editor, the [https://steamcommunity.com/app/312520/discussions/0/1700541698703118028/ original] editor used to create the base game and the [https://store.steampowered.com/news/app/312520/view/3671033323706467799 updated] editor used for the Downpour expansion. The editor functions by using specially formatted spritesheets and a number of programmed effects and outputs PNG files that the engine interprets in 3D (as well as an accompanying text file which contains collision and gameplay info). There are also several unofficial community made Level Editors, the map-editor, a editor that predated the official one and can only edit preexisting maps, the community editor, a community-made edit of the original editor, with new features, bugfixes, and better ease of use, and Drizzle, a community made level renderer that's hardware accelerated. In the future it intends to replace the existing level editors. === Basic Features Overview === Once you've opened/created a level, you are presented with the preview screen of the level, (this preview needs to be manually updated using the "update preview" button whenever changes are made to the level for it to remain accurate.) the buttons can be used to navigate between the different editors, load a new level or save/rename your current level, and export it's geometry data for use in-game. Pressing "1" will bring you back to this screen. It's often best to start by modifying the dimensions of the room to your liking using the level size button before beginning to edit. You can change this at any time, but because you set the dimensions manually rather than visually, making changes later is more difficult and poses the risk of accidentally deleting a portion of your room if you aren't careful. From the dashboard you can switch to the Geometry Editor - used for defining the level geometry and collision, the Tile Editor (for customizing the tiles and assets that make up the geometry created in the geometry editor), the Effects Editor (for adding procedural effects like erosion or slime, as well as things like plants or chains), the Light Editor - for painting light and shadow, or the Prop Editor (for adding additional hand placed props and decals like graffiti). === Controls Overview === ==== View controls (numpad): ==== These are used for every editor view except the Camera and Environment editor to scroll around the screen. Notice, numlock must be turned on for these controls to have any effect. {| class="wikitable" |+ |- ! Key(s) !! Function |- | 8,2,4,6 || Moves view |- | 1 (hold) || Increases view scroll speed. |- | 3 (hold) || Increases view scroll speed even more. |- | 9 (hold) || Allow the view to move outside the boundaries of the level. |} ==== Menu keybinds (Number row): ==== These act as hotkeys to quickly switch between different editor views. These can be used in any editor view as well. {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | 1 || Main menu |- | 2 || Geometry |- | 3 || Tiles |- | 4 || Cameras |- | 5 || Light |- | 6 || Room size |} === Level Settings === ==== Level Size ==== Allows you to set the levels dimensions. You can set the entire level size, and border tiles. Border tiles are padding around the room, mainly for resolutions that are larger than 4:3 (It is recommended to not go under the defaults numbers, as it causes the final render to be cut off.) To calculate the size your level needs to be, you can use the following formula:<br> Width = 52 * Screens + 20<br> Height = 40 * Screens + 3<br> {| class="wikitable" |+ Example Level Sizes |- ! Screens (WxH) !! Width !! Height |- | 1x1 || 72 || 43 |- | 1x2 || 72 || 83 |- | 1x3 || 72 || 123 |- | 1x4 || 72 || 163 |- | 1x5 || 72 || 203 |- | 1x6 || 72 || 243 |- | 2x1 || 124 || 43 |- | 3x1 || 176 || 43 |- | 4x1 || 228 || 43 |- | 5x1 || 280 || 43 |- | 6x1 || 332 || 43 |} ==== Default Medium ==== This determines if you can fall outside of the level or not, death pits still work the same either way however. ==== Light Type ==== The light type can either be set to '''ON''' which will use what you have done in the Light Editor, or '''OFF''' which paints everything in shadow. ==== Seed ==== This is the arrow on the fourth row of bars, which determines what seed the level will use. The seed determines random tile and prop placement, along with how effects are generated. === Rendering === ==== Prioritize Cam ==== Allows you to choose a specific camera to render first. ==== Text Output ==== This outputs a .txt of the level's geometry and collision, usable in-game. ==== Render Level ==== Renders the rooms screens. When a screen is fully rendered it will be in the Levels folder even if the rest of the level hasn't finished rendering. ==== Mass Render ==== Renders every level in the selected folder. === Editors === <tabber> |-|Geometry Editor= == Geometry Editor == [[File: geoEditor.png|400px|thumb|right]] In the Geometry Editor, you define the elements and collision information of your room, such as poles, shortcuts, room entrances, creature dens, and garbage worm placement. (to connect your room to other rooms), and a number of other gameplay relevant elements. === Controls === {| class="wikitable" |+ Geometry editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | Arrow keys || Primary cursor scroll through toolbox. If mouse over the toolbox, mouse moves cursor instead. |- | Mouse || Primary cursor movement. |- | LMB || Primary cursor use current tool. |- | Q (hold) || Secondary cursor scroll through toolbox. |- | E,S,D,F || Secondary cursor movement. |- | W || Secondary cursor use current tool. |} As an experimental feature, the developers implemented a second grey cursor with an alternate control scheme to allow two users to edit a room simultaneously. While as far as we are aware this ended up being a little used feature, it is still implemented and usable in the current editor == Toolbox == {| class="wikitable" |+ Level Editor Geography Tools |- | Inverse || Flips the currently selected tile between walls, and air. |- | Paint Walls || Paints solid tiles. |- | Paint Air || Paints non-solid tiles. |- | Make Slope || Paints a slope, can only be placed inside corners, or the edges of larger solids. |- | Make Floor || Paints thin platforms that entities can stand on that the player can hold down to fall through. |- | Rect Wall || Paints solid tiles in a rectangle. Click two points to set the rectangle's dimensions and paint. |- | Rect Air || Same as above, except for non-solid tiles. |- | Worm Grass || Place above solid ground to spawn worm grass tendrils. The number placed together to the left and right decides the height of the grass. |- | Crack Terrain || Renders as a roughly cracked fissure through the material painted on it in the tile editor. Slugcat can crawl through these tunnels. An example in the vanilla game is in the western temple styled area of the subterranean. Where there are fissures to travel beneath certain stone statues. |- | Horizontal Beam || A Climbable pole. Slugcat can only climb these on layer 1. |- | Vertical Beam || Same as above, except in the other direction. |- | Glass Wall || Paints invisible walls. |- | Waterfall || Will cause a waterfall to appear in game, with this tile at the top of it. |} {| class="wikitable" |+ Level Editor Item and Batfly Tools |- | Place Rock || 60% chance a Rock will spawn at this location. |- | Place Spear || 60% chance a Spear will spawn at this location. |- | Spawn Fly || Does nothing. |- | Forbid Fly Chains || Prevents batflies from hanging together in specific locations. |- | Hive || Places a batfly hive, batflies use these to quickly travel between hives. === Short Cuts and Entrances === [[File: shortcuts_yes.png|270px|thumb|Examples of working shortcuts]] [[File: shortcuts_no.png|270px|right|thumb|Examples of broken shortcuts]] {| class="wikitable" |+ Level Editor Shortcut Tools |- | Short Cut Entrance || Places the entrance of a short cut into the room, these must be fully surrounded by ground except from the entrance side and the exit will always be aiming in the oposite direction of the entrance. When placed on the floor, both players and creatures will fall into them, so its advised to always put a platform in the entrance instead of air in these cases. |- | Short Cut || Places a short cut's travel dot. These can connect two short cut entrances together or connect into a specific entrance or den variation. They can also have no destination, in which case the shortcut entrance will simply be blocked. Short cut dots can cross with each other in a + pattern and each path will always continue forwards. |- | Dragon Den || Places a creature den. These hold the creature assigned to that den in the region's World File. Creatures can move to the closest den if they cant return to their own. |- | Entrance || Used to connect with another room. These can be used by Slugcat and most creatures to travel across a region, the 2 rooms connected by this entrance are determined in the region's World File. |- | Scavenger Hole || Allows scavengers to spawn or travel to this room as they wander through a region. Since scavenger use offscreen dens, all the Scavenger Holes will share the same pool of scavengers. |- | Whack-A-Mole-Hole || Allows creatures to travel arround a room by "teleporting" between these holes. There is no limit to how many holes can be placed in the same room and they are all connected with each other. When a creature enters one of these holes and selects a new destination there is a short period of time in which the shortcut segment glows, so they are often used without Short Cut dots. |- | "G" Garbage Worm den || Unlike the rest of dens, its not attached to a short cut entrance. Instead they are simply placed in the ground tile where we want the Garbage Worm to spawn. |} A short cut dot is not required between the short cut's entrance and the den or door it's connecting to. However, the shortcut must show as an arrow toward the den or door for the link to it to be proper. Short cuts and their connections to the various kinds of entrances in Rain World have specific needs! Improperly making the short cut can lead to crashes, or odd behavior in game. A list of common mistakes include: * Short cuts going outside of the level bounds, anything out of the white frame won't be loaded in game. * Short cut entrances placed directly on the surface. * Short cut entrances with short cut dots on any side which isn't the opposite to the entrance. * Creature dens or room entrances randomly floating in the room disconnected from everything. * Placing Garbage Worm dens connected to an entrance like the other dens. === Layer Info === {| class="wikitable" |+ Level Editor Layer and Misc Tools |- | Copy Backwards || Copies a rectangle of tiles on the current layer to the next layer. This does not wrap around back to layer 1 if you are on layer 3. |- | Work Layer || Changes layers from 1 to 3 and then back to 1. |- | Clear All || Selects a rectangle that resets all tiles inside it, on all layers, back to open air. |- | Toggle Mirror || Turns on and off a mirror tile painting mode. What you do on one side of the mirror will be copied on the other. |- | Move Mirror || Allows you to move the location of the Mirror. |- | Move Level || Moves the whole level in a certain direction. Place the mouse cursor outside the level, then use the arrow keys to move the level in the direction you want. It will not work if your mouse is inside the level as using the arrow keys will swap to another tool. |- | Empty || Does nothing. Good to set as your tool if you have to tab out, as it does nothing. |} Rain World levels consist of 3 layers, each representing a different depth. This layer info is represented visually through the color of tiles, and you can switch between editing on different layers with the work layer tool in the bottom left of the tool panel. Layer 1 draws in full black, layer 2 draws in green, and layer 3 draws in red. These colors will blend if multiple layers are drawn on top of each other. Layer 1 is the foreground, and any filled tiles on this layer will have collision. This is the base layer you define for the sake of gameplay, as any air here is space you can traverse. Layer 2 is the midground, which you can imagine as the back wall of your room. Wall climbing creatures also interact with this. Layer 3 is the extreme background, behind the back wall of the room (for placing distant objects or giving the room a section of open sky). Nothing interacts with this at all. Note: The tile editor defines the visual tiles and props that make up this geometry, so in order to place solid objects in the tile editor (on any layer), those tiles need to be filled here in the geometry editor. Even though the mid-ground and background do not provide any collision geometry, in order to place solid props on those layers the tiles need to be filled here in the geometry editor. Similarly, some props can only be placed on air on the layers (like fences). === Tips and Tricks === - Many of the gameplay features require that they be placed within the margins of your room (represented by the white border). An entrance or creature den placed outside of your margins will render your room un-enterable at best, and crash the game at worst. Short Cut Entrances and Short Cuts can be placed outside the level boundary just fine, however. - Border tiles are tiles that can't be interacted with, and are there for looks only. The room will copy the last tile from the border forever in that direction so be careful with your geometry, or you'll be able to walk out of bounds through "solid" walls or stand in the air. - Because the tool panel loops around from top to bottom and left to right, when editing the base geometry (walls and air) it's faster to use the arrow keys to go up to reach the work layer tool to swap layers than to cycle through the whole list to reach them. Also, the rectangular wall and air tools will let you edit large chunks of your level much faster than going tile by tile. - Because the layers move with a parallax effect, it's often necessary to extend elements on your background layer behind your other layers, otherwise the camera angle will sometimes let you see a gap to the left or right of a background wall and the layer in front of it (for example). It can be just a few tiles extended, unless you have tiles infront that are transparent and reveal behind it. |-|Tile Editor= Full article here [[Tile Editor]]. {| class="wikitable" |+ Tile editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A-D || Flip\scroll through tile categorys |- | W-S || Select tile in current category |- | LMB || Place tile under cursor |- | RMB || Erase tile under cursor |- | F (hold) || Use a 3x3 brush for materials |- | V (hold) || Use a 5x5 brush for materials |- | Tab+x+c || Clears all tiles |- | L || Change active layer (1, 2, 3, loop back to 1) |- | E || Set default material of the room to the currently selected material. |- | F (hold) || Force places selected tile, ignores geometry and erases colliding tiles. |- | G (hold) || Enables force placing selected tile (forcing appropriate geometry for the tile, erasing colliding tiles) |- | Q || "Eyedropper" (selects tile/material hovered over) |} |-|Effect Editor= Full article here [[Effects Editor]]. {| class="wikitable" |+ Effect library keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Select effect category |- | W,S || Select effect in current category |- | E || Switches to editing applied effects |- | Space || Adds selected effect to the stack |} {| class="wikitable" |+ Applied effect keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,S || Scroll through the effect stack |- | N || Switch to effect library |- | Space || Edit selected effect in the stack |} Effect editing: {| class="wikitable" |+ Effect editing keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Scroll through options in the effect's menu |- | W,S || Changes the current effect's menu |- | Space || Activates selected option in the effect's menu |- | LMB || Paints effect in the level |- | RMB || Erases effect in the level |- | R || Brush size up |- | F || Brush size down |- | E || Switch to effect stack |- | N || Switch to effect library |} |-|Camera Editor= Full article here Camera Editor. N - New camera, spawns held by mouse E - grab a camera if none is held D - Delete held camera P - Place held camera Note: A maximum of 20 Cameras can be placed per level |-|Light editor= Full article here [[Light Editor]]. {| class="wikitable" |+ Light editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,A,S,D || Scale current light shape |- | Q,E || Rotate current light shape |- | Z || Toggle between drawing and erasing light |- | LMB || Paint light |- | RMB (hold) || Rotate light shape in direction of mouse ( does not paint it.) |- | R,F || Scroll through light shape library |- | J,L || Change angle of light source |- | I,K || Change distance of light source |} |-|Prop Editor= Full article here [[Prop Editor]]. {| class="wikitable" |+ Prop editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A, D || Changes prop library's category |- | W, S || Scrolls through props in current category |- | LMB || Place current prop |- | V (hold) || LMB erases highlighted prop |- | Q,E || Rotate prop left and right |- | Space (hold) || Speed up rotation |- | Y,G,H,J || Stretch prop |- | T || Reset prop stretching |- | R || reset stretching, and rotation |- | Y, H || (on wire/tube props) increases or decreases prop's physics node count. Less means more taught, more means more loose. |- | X || Pause wire/tube physics |- | Tab+X+C || Clear all props |- | B || Click mouse left to set the highlighted prop as the currently selected prop. |- | L || Change layer |- | RMB || Cycle depth in current layer (10 sublevels). |- | Space + RMB || Cycle depth in current layer, reverse direction. |- | U-I-O-P (hold) || Freeform stretch by one of the corners (U - top right, I - bottom right, O - bottom left, and P - top left.) |- | K || resets freeform stretching. |- | N || Switches to editing properties menu of the prop. Things like forcing certain graffiti to be drawn instead of a random one. |- | M (hold) || LMB opens properties of an already placed prop instead of placing a prop (same menu as above) |- | Z || Changes prop color |- | F + LMB/RMB || Changes between prop variants. This only applies to certain props. |} |-|Environment Editor= {| class="wikitable" |+ Environment editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | L || Set water level to mouse pointer |- | F || Toggles between drawing water above the first layer or below it. |- | W || Toggle water on level |} </tabber> == Crash Avoidance and Editor Quirks == Due to the editor being extremely user unfriendly, you are likely to run into various crashes without warning. This is a list of various things to avoid doing. === Crashes: === Do not switch to editing applied effects in the Effects Editor when there are none. The switch will be invisible, and attempting to use the space bar to select something from there will crash the Level Editor. Some effects have very specific conditions and cause issues when rendering, Effects include: Thick Roots, and Shadow Plants. these ones can be okayed through until it renders.) Be sure to remove tiles from parts of a room that will be removed if you resize the room to cut those areas out, those tiles are still recorded, and will crash renders instantly. props are the exact same as above Never render with no cameras. It will crash. Always move the prop menu into an actual category when you open it, it keeps the last menu used, and crashes if you select any entry that is not a real prop. (EX: it will have the effects menu, or tile menu.) If you are using the Mirrored tile placer, in the geometry editor. Placing poles, with the other side of the mirrored brush being outside of the room, will crash the editor. === Quirks: === The main menu is a mess when you return from using the Light Editor or the Environment Editor. Just change to any other editor (geometry or tiles, and back to main menu) to clean it. This is not a crash, but will help prevent confusion if you know to expect this. To use the Move and Move Mirror tools in the editor, you must first select them, and then move your mouse outside of the room itself, before it will respond to your inputs. Usually you will only need to put your mouse over the editor, but in larger rooms, this is often an issue, as the room is "behind" the menu, and thus only changes tool selection. The editor still receives inputs if you only tab out using alt-tab. When viewing another window, it's important to always minimize the editor, because there are many things that can go wrong if you're randomly clicking in the editor. (Requires more confirmation) The screen during rendering should usually show the map being rendered, but it may not. In the task manager, The Rain World Editor is under the tab Adobe Projector. Sometimes the reason it is not showing is a second application called "Print driver host for applications". Closing the application seems to fix the issue. The window for the application may be too big to fit on screen, and cannot be fixed since reaching the top bar or right clicking cannot be accessed to move the window. === Demo and Tutorial Videos === Region Developer Kaeporo created a tutorial for creating levels in and out of the level editor: {{#ev:youtube|YQ0DO-fmPCE|||||urlargs=""}} Mod community member Sacretis also put together a demonstration video, this time covering the creation of a room from scratch to visual polish (massively sped up for the sake of time): {{#ev:youtube|sEE3X1izaJA|||||urlargs=""}} 4506cafa3a0247c91f94f4461b7022a85d6b57a8 521 516 2023-06-30T02:32:25Z Artificer 123 rewrote some stuff for clarity wikitext text/x-wiki {{Cleanup}} == The Official Level Editor == [[File:editorFront.png|400px|thumb|right]] The Level Editor is an application created by the Rain World developers in order to create new in-game rooms and edit existing ones. There are two officially released versions of the editor, the [https://steamcommunity.com/app/312520/discussions/0/1700541698703118028/ original] editor used to create the base game and the [https://store.steampowered.com/news/app/312520/view/3671033323706467799 updated] editor used for the Downpour expansion. The editor functions by using specially formatted spritesheets and a number of programmed effects and outputs PNG files that the engine interprets in 3D (as well as an accompanying text file which contains collision and gameplay info). There are also several unofficial community made Level Editors: including the map-editor, which predated the official one and can only edit preexisting maps; the community editor, a community-made edit of the original editor with new features, bugfixes, and better ease of use; and Drizzle, a community made level renderer that is able to render levels several times faster, and in the future intends to replace the existing level editors. === Basic Features Overview === Once you've opened/created a level, you are presented with the preview screen of the level, although this preview needs to be manually updated using the "update preview" button whenever changes are made to the level for it to remain accurate. The buttons can be used to navigate between the different editors, load a new level, or save/rename your current level and export it's geometry data for use in-game. Pressing "1" will bring you back to this screen. It's often best to start by modifying the dimensions of the room to your liking using the level size button before beginning to edit. You can change this at any time, but because you set the dimensions manually rather than visually, making changes later is more difficult and poses the risk of accidentally deleting a portion of your room if you aren't careful. From the dashboard you can switch to the Geometry Editor - used for defining the level geometry and collision, the Tile Editor (for customizing the tiles and assets that make up the geometry created in the geometry editor), the Effects Editor (for adding procedural effects like erosion or slime, as well as things like plants or chains), the Light Editor - for painting light and shadow, or the Prop Editor (for adding additional hand placed props and decals like graffiti). === Controls Overview === ==== View controls (numpad): ==== These are used for every editor view except the Camera and Environment editor to scroll around the screen. Notice, numlock must be turned on for these controls to have any effect. {| class="wikitable" |+ |- ! Key(s) !! Function |- | 8,2,4,6 || Moves view |- | 1 (hold) || Increases view scroll speed. |- | 3 (hold) || Increases view scroll speed even more. |- | 9 (hold) || Allow the view to move outside the boundaries of the level. |} ==== Menu keybinds (Number row): ==== These act as hotkeys to quickly switch between different editor views. These can be used in any editor view as well. {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | 1 || Main menu |- | 2 || Geometry |- | 3 || Tiles |- | 4 || Cameras |- | 5 || Light |- | 6 || Room size |} === Level Settings === ==== Level Size ==== Allows you to set the levels dimensions. You can set the entire level size, and border tiles. Border tiles are padding around the room, mainly for resolutions that are larger than 4:3 (It is recommended to not go under the defaults numbers, as it causes the final render to be cut off.) To calculate the size your level needs to be, you can use the following formula:<br> Width = 52 * Screens + 20<br> Height = 40 * Screens + 3<br> {| class="wikitable" |+ Example Level Sizes |- ! Screens (WxH) !! Width !! Height |- | 1x1 || 72 || 43 |- | 1x2 || 72 || 83 |- | 1x3 || 72 || 123 |- | 1x4 || 72 || 163 |- | 1x5 || 72 || 203 |- | 1x6 || 72 || 243 |- | 2x1 || 124 || 43 |- | 3x1 || 176 || 43 |- | 4x1 || 228 || 43 |- | 5x1 || 280 || 43 |- | 6x1 || 332 || 43 |} ==== Default Medium ==== This determines if you can fall outside of the level or not, death pits still work the same either way however. ==== Light Type ==== The light type can either be set to '''ON''' which will use what you have done in the Light Editor, or '''OFF''' which paints everything in shadow. ==== Seed ==== This is the arrow on the fourth row of bars, which determines what seed the level will use. The seed determines random tile and prop placement, along with how effects are generated. === Rendering === ==== Prioritize Cam ==== Allows you to choose a specific camera to render first. ==== Text Output ==== This outputs a .txt of the level's geometry and collision, usable in-game. ==== Render Level ==== Renders the rooms screens. When a screen is fully rendered it will be in the Levels folder even if the rest of the level hasn't finished rendering. ==== Mass Render ==== Renders every level in the selected folder. === Editors === <tabber> |-|Geometry Editor= == Geometry Editor == [[File: geoEditor.png|400px|thumb|right]] In the Geometry Editor, you define the elements and collision information of your room, such as poles, shortcuts, room entrances, creature dens, and garbage worm placement. (to connect your room to other rooms), and a number of other gameplay relevant elements. === Controls === {| class="wikitable" |+ Geometry editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | Arrow keys || Primary cursor scroll through toolbox. If mouse over the toolbox, mouse moves cursor instead. |- | Mouse || Primary cursor movement. |- | LMB || Primary cursor use current tool. |- | Q (hold) || Secondary cursor scroll through toolbox. |- | E,S,D,F || Secondary cursor movement. |- | W || Secondary cursor use current tool. |} As an experimental feature, the developers implemented a second grey cursor with an alternate control scheme to allow two users to edit a room simultaneously. While as far as we are aware this ended up being a little used feature, it is still implemented and usable in the current editor == Toolbox == {| class="wikitable" |+ Level Editor Geography Tools |- | Inverse || Flips the currently selected tile between walls, and air. |- | Paint Walls || Paints solid tiles. |- | Paint Air || Paints non-solid tiles. |- | Make Slope || Paints a slope, can only be placed inside corners, or the edges of larger solids. |- | Make Floor || Paints thin platforms that entities can stand on that the player can hold down to fall through. |- | Rect Wall || Paints solid tiles in a rectangle. Click two points to set the rectangle's dimensions and paint. |- | Rect Air || Same as above, except for non-solid tiles. |- | Worm Grass || Place above solid ground to spawn worm grass tendrils. The number placed together to the left and right decides the height of the grass. |- | Crack Terrain || Renders as a roughly cracked fissure through the material painted on it in the tile editor. Slugcat can crawl through these tunnels. An example in the vanilla game is in the western temple styled area of the subterranean. Where there are fissures to travel beneath certain stone statues. |- | Horizontal Beam || A Climbable pole. Slugcat can only climb these on layer 1. |- | Vertical Beam || Same as above, except in the other direction. |- | Glass Wall || Paints invisible walls. |- | Waterfall || Will cause a waterfall to appear in game, with this tile at the top of it. |} {| class="wikitable" |+ Level Editor Item and Batfly Tools |- | Place Rock || 60% chance a Rock will spawn at this location. |- | Place Spear || 60% chance a Spear will spawn at this location. |- | Spawn Fly || Does nothing. |- | Forbid Fly Chains || Prevents batflies from hanging together in specific locations. |- | Hive || Places a batfly hive, batflies use these to quickly travel between hives. === Short Cuts and Entrances === [[File: shortcuts_yes.png|270px|thumb|Examples of working shortcuts]] [[File: shortcuts_no.png|270px|right|thumb|Examples of broken shortcuts]] {| class="wikitable" |+ Level Editor Shortcut Tools |- | Short Cut Entrance || Places the entrance of a short cut into the room, these must be fully surrounded by ground except from the entrance side and the exit will always be aiming in the oposite direction of the entrance. When placed on the floor, both players and creatures will fall into them, so its advised to always put a platform in the entrance instead of air in these cases. |- | Short Cut || Places a short cut's travel dot. These can connect two short cut entrances together or connect into a specific entrance or den variation. They can also have no destination, in which case the shortcut entrance will simply be blocked. Short cut dots can cross with each other in a + pattern and each path will always continue forwards. |- | Dragon Den || Places a creature den. These hold the creature assigned to that den in the region's World File. Creatures can move to the closest den if they cant return to their own. |- | Entrance || Used to connect with another room. These can be used by Slugcat and most creatures to travel across a region, the 2 rooms connected by this entrance are determined in the region's World File. |- | Scavenger Hole || Allows scavengers to spawn or travel to this room as they wander through a region. Since scavenger use offscreen dens, all the Scavenger Holes will share the same pool of scavengers. |- | Whack-A-Mole-Hole || Allows creatures to travel arround a room by "teleporting" between these holes. There is no limit to how many holes can be placed in the same room and they are all connected with each other. When a creature enters one of these holes and selects a new destination there is a short period of time in which the shortcut segment glows, so they are often used without Short Cut dots. |- | "G" Garbage Worm den || Unlike the rest of dens, its not attached to a short cut entrance. Instead they are simply placed in the ground tile where we want the Garbage Worm to spawn. |} A short cut dot is not required between the short cut's entrance and the den or door it's connecting to. However, the shortcut must show as an arrow toward the den or door for the link to it to be proper. Short cuts and their connections to the various kinds of entrances in Rain World have specific needs! Improperly making the short cut can lead to crashes, or odd behavior in game. A list of common mistakes include: * Short cuts going outside of the level bounds, anything out of the white frame won't be loaded in game. * Short cut entrances placed directly on the surface. * Short cut entrances with short cut dots on any side which isn't the opposite to the entrance. * Creature dens or room entrances randomly floating in the room disconnected from everything. * Placing Garbage Worm dens connected to an entrance like the other dens. === Layer Info === {| class="wikitable" |+ Level Editor Layer and Misc Tools |- | Copy Backwards || Copies a rectangle of tiles on the current layer to the next layer. This does not wrap around back to layer 1 if you are on layer 3. |- | Work Layer || Changes layers from 1 to 3 and then back to 1. |- | Clear All || Selects a rectangle that resets all tiles inside it, on all layers, back to open air. |- | Toggle Mirror || Turns on and off a mirror tile painting mode. What you do on one side of the mirror will be copied on the other. |- | Move Mirror || Allows you to move the location of the Mirror. |- | Move Level || Moves the whole level in a certain direction. Place the mouse cursor outside the level, then use the arrow keys to move the level in the direction you want. It will not work if your mouse is inside the level as using the arrow keys will swap to another tool. |- | Empty || Does nothing. Good to set as your tool if you have to tab out, as it does nothing. |} Rain World levels consist of 3 layers, each representing a different depth. This layer info is represented visually through the color of tiles, and you can switch between editing on different layers with the work layer tool in the bottom left of the tool panel. Layer 1 draws in full black, layer 2 draws in green, and layer 3 draws in red. These colors will blend if multiple layers are drawn on top of each other. Layer 1 is the foreground, and any filled tiles on this layer will have collision. This is the base layer you define for the sake of gameplay, as any air here is space you can traverse. Layer 2 is the midground, which you can imagine as the back wall of your room. Wall climbing creatures also interact with this. Layer 3 is the extreme background, behind the back wall of the room (for placing distant objects or giving the room a section of open sky). Nothing interacts with this at all. Note: The tile editor defines the visual tiles and props that make up this geometry, so in order to place solid objects in the tile editor (on any layer), those tiles need to be filled here in the geometry editor. Even though the mid-ground and background do not provide any collision geometry, in order to place solid props on those layers the tiles need to be filled here in the geometry editor. Similarly, some props can only be placed on air on the layers (like fences). === Tips and Tricks === - Many of the gameplay features require that they be placed within the margins of your room (represented by the white border). An entrance or creature den placed outside of your margins will render your room un-enterable at best, and crash the game at worst. Short Cut Entrances and Short Cuts can be placed outside the level boundary just fine, however. - Border tiles are tiles that can't be interacted with, and are there for looks only. The room will copy the last tile from the border forever in that direction so be careful with your geometry, or you'll be able to walk out of bounds through "solid" walls or stand in the air. - Because the tool panel loops around from top to bottom and left to right, when editing the base geometry (walls and air) it's faster to use the arrow keys to go up to reach the work layer tool to swap layers than to cycle through the whole list to reach them. Also, the rectangular wall and air tools will let you edit large chunks of your level much faster than going tile by tile. - Because the layers move with a parallax effect, it's often necessary to extend elements on your background layer behind your other layers, otherwise the camera angle will sometimes let you see a gap to the left or right of a background wall and the layer in front of it (for example). It can be just a few tiles extended, unless you have tiles infront that are transparent and reveal behind it. |-|Tile Editor= Full article here [[Tile Editor]]. {| class="wikitable" |+ Tile editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A-D || Flip\scroll through tile categorys |- | W-S || Select tile in current category |- | LMB || Place tile under cursor |- | RMB || Erase tile under cursor |- | F (hold) || Use a 3x3 brush for materials |- | V (hold) || Use a 5x5 brush for materials |- | Tab+x+c || Clears all tiles |- | L || Change active layer (1, 2, 3, loop back to 1) |- | E || Set default material of the room to the currently selected material. |- | F (hold) || Force places selected tile, ignores geometry and erases colliding tiles. |- | G (hold) || Enables force placing selected tile (forcing appropriate geometry for the tile, erasing colliding tiles) |- | Q || "Eyedropper" (selects tile/material hovered over) |} |-|Effect Editor= Full article here [[Effects Editor]]. {| class="wikitable" |+ Effect library keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Select effect category |- | W,S || Select effect in current category |- | E || Switches to editing applied effects |- | Space || Adds selected effect to the stack |} {| class="wikitable" |+ Applied effect keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,S || Scroll through the effect stack |- | N || Switch to effect library |- | Space || Edit selected effect in the stack |} Effect editing: {| class="wikitable" |+ Effect editing keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Scroll through options in the effect's menu |- | W,S || Changes the current effect's menu |- | Space || Activates selected option in the effect's menu |- | LMB || Paints effect in the level |- | RMB || Erases effect in the level |- | R || Brush size up |- | F || Brush size down |- | E || Switch to effect stack |- | N || Switch to effect library |} |-|Camera Editor= Full article here Camera Editor. N - New camera, spawns held by mouse E - grab a camera if none is held D - Delete held camera P - Place held camera Note: A maximum of 20 Cameras can be placed per level |-|Light editor= Full article here [[Light Editor]]. {| class="wikitable" |+ Light editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,A,S,D || Scale current light shape |- | Q,E || Rotate current light shape |- | Z || Toggle between drawing and erasing light |- | LMB || Paint light |- | RMB (hold) || Rotate light shape in direction of mouse ( does not paint it.) |- | R,F || Scroll through light shape library |- | J,L || Change angle of light source |- | I,K || Change distance of light source |} |-|Prop Editor= Full article here [[Prop Editor]]. {| class="wikitable" |+ Prop editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A, D || Changes prop library's category |- | W, S || Scrolls through props in current category |- | LMB || Place current prop |- | V (hold) || LMB erases highlighted prop |- | Q,E || Rotate prop left and right |- | Space (hold) || Speed up rotation |- | Y,G,H,J || Stretch prop |- | T || Reset prop stretching |- | R || reset stretching, and rotation |- | Y, H || (on wire/tube props) increases or decreases prop's physics node count. Less means more taught, more means more loose. |- | X || Pause wire/tube physics |- | Tab+X+C || Clear all props |- | B || Click mouse left to set the highlighted prop as the currently selected prop. |- | L || Change layer |- | RMB || Cycle depth in current layer (10 sublevels). |- | Space + RMB || Cycle depth in current layer, reverse direction. |- | U-I-O-P (hold) || Freeform stretch by one of the corners (U - top right, I - bottom right, O - bottom left, and P - top left.) |- | K || resets freeform stretching. |- | N || Switches to editing properties menu of the prop. Things like forcing certain graffiti to be drawn instead of a random one. |- | M (hold) || LMB opens properties of an already placed prop instead of placing a prop (same menu as above) |- | Z || Changes prop color |- | F + LMB/RMB || Changes between prop variants. This only applies to certain props. |} |-|Environment Editor= {| class="wikitable" |+ Environment editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | L || Set water level to mouse pointer |- | F || Toggles between drawing water above the first layer or below it. |- | W || Toggle water on level |} </tabber> == Crash Avoidance and Editor Quirks == Due to the editor being extremely user unfriendly, you are likely to run into various crashes without warning. This is a list of various things to avoid doing. === Crashes: === Do not switch to editing applied effects in the Effects Editor when there are none. The switch will be invisible, and attempting to use the space bar to select something from there will crash the Level Editor. Some effects have very specific conditions and cause issues when rendering, Effects include: Thick Roots, and Shadow Plants. these ones can be okayed through until it renders.) Be sure to remove tiles from parts of a room that will be removed if you resize the room to cut those areas out, those tiles are still recorded, and will crash renders instantly. props are the exact same as above Never render with no cameras. It will crash. Always move the prop menu into an actual category when you open it, it keeps the last menu used, and crashes if you select any entry that is not a real prop. (EX: it will have the effects menu, or tile menu.) If you are using the Mirrored tile placer, in the geometry editor. Placing poles, with the other side of the mirrored brush being outside of the room, will crash the editor. === Quirks: === The main menu is a mess when you return from using the Light Editor or the Environment Editor. Just change to any other editor (geometry or tiles, and back to main menu) to clean it. This is not a crash, but will help prevent confusion if you know to expect this. To use the Move and Move Mirror tools in the editor, you must first select them, and then move your mouse outside of the room itself, before it will respond to your inputs. Usually you will only need to put your mouse over the editor, but in larger rooms, this is often an issue, as the room is "behind" the menu, and thus only changes tool selection. The editor still receives inputs if you only tab out using alt-tab. When viewing another window, it's important to always minimize the editor, because there are many things that can go wrong if you're randomly clicking in the editor. (Requires more confirmation) The screen during rendering should usually show the map being rendered, but it may not. In the task manager, The Rain World Editor is under the tab Adobe Projector. Sometimes the reason it is not showing is a second application called "Print driver host for applications". Closing the application seems to fix the issue. The window for the application may be too big to fit on screen, and cannot be fixed since reaching the top bar or right clicking cannot be accessed to move the window. === Demo and Tutorial Videos === Region Developer Kaeporo created a tutorial for creating levels in and out of the level editor: {{#ev:youtube|YQ0DO-fmPCE|||||urlargs=""}} Mod community member Sacretis also put together a demonstration video, this time covering the creation of a room from scratch to visual polish (massively sped up for the sake of time): {{#ev:youtube|sEE3X1izaJA|||||urlargs=""}} c202eff0e0a733ae455470a2f4d50f71883849a7 522 521 2023-06-30T02:34:34Z Artificer 123 clarity wikitext text/x-wiki {{Cleanup}} == The Official Level Editor == [[File:editorFront.png|400px|thumb|right]] The Level Editor is an application created by the Rain World developers in order to create new in-game rooms and edit existing ones. There are two officially released versions of the editor, the [https://steamcommunity.com/app/312520/discussions/0/1700541698703118028/ original] editor used to create the base game and the [https://store.steampowered.com/news/app/312520/view/3671033323706467799 updated] editor used for the Downpour expansion. The editor functions by using specially formatted spritesheets and a number of programmed effects and outputs PNG files that the engine interprets in 3D (as well as an accompanying text file which contains collision and gameplay info). There are also several unofficial community made Level Editors: including the map-editor, which predated the official one and can only edit preexisting maps; the community editor, a community-made edit of the original editor with new features, bugfixes, and better ease of use; and Drizzle, a community made level renderer that is able to render levels several times faster, and in the future intends to replace the existing level editors. === Basic Features Overview === Once you've opened/created a level, you are presented with the preview screen of the level, although this preview needs to be manually updated using the "update preview" button whenever changes are made to the level for it to remain accurate. The buttons can be used to navigate between the different editors, load a new level, or save/rename your current level and export it's geometry data for use in-game. Pressing "1" will bring you back to this screen. It's often best to start by modifying the dimensions of the room to your liking using the level size button before beginning to edit. You can change this at any time, but because you set the dimensions manually rather than visually, making changes later is more difficult and poses the risk of accidentally deleting a portion of your room if you aren't careful. From the dashboard you can switch to the Geometry Editor - used for defining the level geometry and collision, the Tile Editor (for customizing the tiles and assets that make up the geometry created in the geometry editor), the Effects Editor (for adding procedural effects like erosion or slime, as well as things like plants or chains), the Light Editor - for painting light and shadow, or the Prop Editor (for adding additional hand placed props and decals like graffiti). === Controls Overview === ==== View controls (numpad): ==== These are used for every editor view, except for the Camera and Environment editor, to scroll around the screen. Note that numlock must be turned on for these controls to have any effect. {| class="wikitable" |+ |- ! Key(s) !! Function |- | 8,2,4,6 || Moves view |- | 1 (hold) || Increases view scroll speed. |- | 3 (hold) || Increases view scroll speed even more. |- | 9 (hold) || Allow the view to move outside the boundaries of the level. |} ==== Menu keybinds (Number row): ==== These act as hotkeys to quickly switch between different editor views. These can be used in any editor view as well. {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | 1 || Main menu |- | 2 || Geometry |- | 3 || Tiles |- | 4 || Cameras |- | 5 || Light |- | 6 || Room size |} === Level Settings === ==== Level Size ==== Allows you to set the levels dimensions. You can set the entire level size, and border tiles. Border tiles are padding around the room, mainly for resolutions that are larger than 4:3 (It is recommended to not go under the defaults numbers, as it causes the final render to be cut off.) To calculate the size your level needs to be, you can use the following formula:<br> Width = 52 * Screens + 20<br> Height = 40 * Screens + 3<br> {| class="wikitable" |+ Example Level Sizes |- ! Screens (WxH) !! Width !! Height |- | 1x1 || 72 || 43 |- | 1x2 || 72 || 83 |- | 1x3 || 72 || 123 |- | 1x4 || 72 || 163 |- | 1x5 || 72 || 203 |- | 1x6 || 72 || 243 |- | 2x1 || 124 || 43 |- | 3x1 || 176 || 43 |- | 4x1 || 228 || 43 |- | 5x1 || 280 || 43 |- | 6x1 || 332 || 43 |} ==== Default Medium ==== This determines if you can fall outside of the level or not, death pits still work the same either way however. ==== Light Type ==== The light type can either be set to '''ON''' which will use what you have done in the Light Editor, or '''OFF''' which paints everything in shadow. ==== Seed ==== This is the arrow on the fourth row of bars, which determines what seed the level will use. The seed determines random tile and prop placement, along with how effects are generated. === Rendering === ==== Prioritize Cam ==== Allows you to choose a specific camera to render first. ==== Text Output ==== This outputs a .txt of the level's geometry and collision, usable in-game. ==== Render Level ==== Renders the rooms screens. When a screen is fully rendered it will be in the Levels folder even if the rest of the level hasn't finished rendering. ==== Mass Render ==== Renders every level in the selected folder. === Editors === <tabber> |-|Geometry Editor= == Geometry Editor == [[File: geoEditor.png|400px|thumb|right]] In the Geometry Editor, you define the elements and collision information of your room, such as poles, shortcuts, room entrances, creature dens, and garbage worm placement. (to connect your room to other rooms), and a number of other gameplay relevant elements. === Controls === {| class="wikitable" |+ Geometry editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | Arrow keys || Primary cursor scroll through toolbox. If mouse over the toolbox, mouse moves cursor instead. |- | Mouse || Primary cursor movement. |- | LMB || Primary cursor use current tool. |- | Q (hold) || Secondary cursor scroll through toolbox. |- | E,S,D,F || Secondary cursor movement. |- | W || Secondary cursor use current tool. |} As an experimental feature, the developers implemented a second grey cursor with an alternate control scheme to allow two users to edit a room simultaneously. While as far as we are aware this ended up being a little used feature, it is still implemented and usable in the current editor == Toolbox == {| class="wikitable" |+ Level Editor Geography Tools |- | Inverse || Flips the currently selected tile between walls, and air. |- | Paint Walls || Paints solid tiles. |- | Paint Air || Paints non-solid tiles. |- | Make Slope || Paints a slope, can only be placed inside corners, or the edges of larger solids. |- | Make Floor || Paints thin platforms that entities can stand on that the player can hold down to fall through. |- | Rect Wall || Paints solid tiles in a rectangle. Click two points to set the rectangle's dimensions and paint. |- | Rect Air || Same as above, except for non-solid tiles. |- | Worm Grass || Place above solid ground to spawn worm grass tendrils. The number placed together to the left and right decides the height of the grass. |- | Crack Terrain || Renders as a roughly cracked fissure through the material painted on it in the tile editor. Slugcat can crawl through these tunnels. An example in the vanilla game is in the western temple styled area of the subterranean. Where there are fissures to travel beneath certain stone statues. |- | Horizontal Beam || A Climbable pole. Slugcat can only climb these on layer 1. |- | Vertical Beam || Same as above, except in the other direction. |- | Glass Wall || Paints invisible walls. |- | Waterfall || Will cause a waterfall to appear in game, with this tile at the top of it. |} {| class="wikitable" |+ Level Editor Item and Batfly Tools |- | Place Rock || 60% chance a Rock will spawn at this location. |- | Place Spear || 60% chance a Spear will spawn at this location. |- | Spawn Fly || Does nothing. |- | Forbid Fly Chains || Prevents batflies from hanging together in specific locations. |- | Hive || Places a batfly hive, batflies use these to quickly travel between hives. === Short Cuts and Entrances === [[File: shortcuts_yes.png|270px|thumb|Examples of working shortcuts]] [[File: shortcuts_no.png|270px|right|thumb|Examples of broken shortcuts]] {| class="wikitable" |+ Level Editor Shortcut Tools |- | Short Cut Entrance || Places the entrance of a short cut into the room, these must be fully surrounded by ground except from the entrance side and the exit will always be aiming in the oposite direction of the entrance. When placed on the floor, both players and creatures will fall into them, so its advised to always put a platform in the entrance instead of air in these cases. |- | Short Cut || Places a short cut's travel dot. These can connect two short cut entrances together or connect into a specific entrance or den variation. They can also have no destination, in which case the shortcut entrance will simply be blocked. Short cut dots can cross with each other in a + pattern and each path will always continue forwards. |- | Dragon Den || Places a creature den. These hold the creature assigned to that den in the region's World File. Creatures can move to the closest den if they cant return to their own. |- | Entrance || Used to connect with another room. These can be used by Slugcat and most creatures to travel across a region, the 2 rooms connected by this entrance are determined in the region's World File. |- | Scavenger Hole || Allows scavengers to spawn or travel to this room as they wander through a region. Since scavenger use offscreen dens, all the Scavenger Holes will share the same pool of scavengers. |- | Whack-A-Mole-Hole || Allows creatures to travel arround a room by "teleporting" between these holes. There is no limit to how many holes can be placed in the same room and they are all connected with each other. When a creature enters one of these holes and selects a new destination there is a short period of time in which the shortcut segment glows, so they are often used without Short Cut dots. |- | "G" Garbage Worm den || Unlike the rest of dens, its not attached to a short cut entrance. Instead they are simply placed in the ground tile where we want the Garbage Worm to spawn. |} A short cut dot is not required between the short cut's entrance and the den or door it's connecting to. However, the shortcut must show as an arrow toward the den or door for the link to it to be proper. Short cuts and their connections to the various kinds of entrances in Rain World have specific needs! Improperly making the short cut can lead to crashes, or odd behavior in game. A list of common mistakes include: * Short cuts going outside of the level bounds, anything out of the white frame won't be loaded in game. * Short cut entrances placed directly on the surface. * Short cut entrances with short cut dots on any side which isn't the opposite to the entrance. * Creature dens or room entrances randomly floating in the room disconnected from everything. * Placing Garbage Worm dens connected to an entrance like the other dens. === Layer Info === {| class="wikitable" |+ Level Editor Layer and Misc Tools |- | Copy Backwards || Copies a rectangle of tiles on the current layer to the next layer. This does not wrap around back to layer 1 if you are on layer 3. |- | Work Layer || Changes layers from 1 to 3 and then back to 1. |- | Clear All || Selects a rectangle that resets all tiles inside it, on all layers, back to open air. |- | Toggle Mirror || Turns on and off a mirror tile painting mode. What you do on one side of the mirror will be copied on the other. |- | Move Mirror || Allows you to move the location of the Mirror. |- | Move Level || Moves the whole level in a certain direction. Place the mouse cursor outside the level, then use the arrow keys to move the level in the direction you want. It will not work if your mouse is inside the level as using the arrow keys will swap to another tool. |- | Empty || Does nothing. Good to set as your tool if you have to tab out, as it does nothing. |} Rain World levels consist of 3 layers, each representing a different depth. This layer info is represented visually through the color of tiles, and you can switch between editing on different layers with the work layer tool in the bottom left of the tool panel. Layer 1 draws in full black, layer 2 draws in green, and layer 3 draws in red. These colors will blend if multiple layers are drawn on top of each other. Layer 1 is the foreground, and any filled tiles on this layer will have collision. This is the base layer you define for the sake of gameplay, as any air here is space you can traverse. Layer 2 is the midground, which you can imagine as the back wall of your room. Wall climbing creatures also interact with this. Layer 3 is the extreme background, behind the back wall of the room (for placing distant objects or giving the room a section of open sky). Nothing interacts with this at all. Note: The tile editor defines the visual tiles and props that make up this geometry, so in order to place solid objects in the tile editor (on any layer), those tiles need to be filled here in the geometry editor. Even though the mid-ground and background do not provide any collision geometry, in order to place solid props on those layers the tiles need to be filled here in the geometry editor. Similarly, some props can only be placed on air on the layers (like fences). === Tips and Tricks === - Many of the gameplay features require that they be placed within the margins of your room (represented by the white border). An entrance or creature den placed outside of your margins will render your room un-enterable at best, and crash the game at worst. Short Cut Entrances and Short Cuts can be placed outside the level boundary just fine, however. - Border tiles are tiles that can't be interacted with, and are there for looks only. The room will copy the last tile from the border forever in that direction so be careful with your geometry, or you'll be able to walk out of bounds through "solid" walls or stand in the air. - Because the tool panel loops around from top to bottom and left to right, when editing the base geometry (walls and air) it's faster to use the arrow keys to go up to reach the work layer tool to swap layers than to cycle through the whole list to reach them. Also, the rectangular wall and air tools will let you edit large chunks of your level much faster than going tile by tile. - Because the layers move with a parallax effect, it's often necessary to extend elements on your background layer behind your other layers, otherwise the camera angle will sometimes let you see a gap to the left or right of a background wall and the layer in front of it (for example). It can be just a few tiles extended, unless you have tiles infront that are transparent and reveal behind it. |-|Tile Editor= Full article here [[Tile Editor]]. {| class="wikitable" |+ Tile editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A-D || Flip\scroll through tile categorys |- | W-S || Select tile in current category |- | LMB || Place tile under cursor |- | RMB || Erase tile under cursor |- | F (hold) || Use a 3x3 brush for materials |- | V (hold) || Use a 5x5 brush for materials |- | Tab+x+c || Clears all tiles |- | L || Change active layer (1, 2, 3, loop back to 1) |- | E || Set default material of the room to the currently selected material. |- | F (hold) || Force places selected tile, ignores geometry and erases colliding tiles. |- | G (hold) || Enables force placing selected tile (forcing appropriate geometry for the tile, erasing colliding tiles) |- | Q || "Eyedropper" (selects tile/material hovered over) |} |-|Effect Editor= Full article here [[Effects Editor]]. {| class="wikitable" |+ Effect library keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Select effect category |- | W,S || Select effect in current category |- | E || Switches to editing applied effects |- | Space || Adds selected effect to the stack |} {| class="wikitable" |+ Applied effect keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,S || Scroll through the effect stack |- | N || Switch to effect library |- | Space || Edit selected effect in the stack |} Effect editing: {| class="wikitable" |+ Effect editing keybinds |- ! '''Key(s)''' !! '''Function''' |- | A,D || Scroll through options in the effect's menu |- | W,S || Changes the current effect's menu |- | Space || Activates selected option in the effect's menu |- | LMB || Paints effect in the level |- | RMB || Erases effect in the level |- | R || Brush size up |- | F || Brush size down |- | E || Switch to effect stack |- | N || Switch to effect library |} |-|Camera Editor= Full article here Camera Editor. N - New camera, spawns held by mouse E - grab a camera if none is held D - Delete held camera P - Place held camera Note: A maximum of 20 Cameras can be placed per level |-|Light editor= Full article here [[Light Editor]]. {| class="wikitable" |+ Light editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,A,S,D || Scale current light shape |- | Q,E || Rotate current light shape |- | Z || Toggle between drawing and erasing light |- | LMB || Paint light |- | RMB (hold) || Rotate light shape in direction of mouse ( does not paint it.) |- | R,F || Scroll through light shape library |- | J,L || Change angle of light source |- | I,K || Change distance of light source |} |-|Prop Editor= Full article here [[Prop Editor]]. {| class="wikitable" |+ Prop editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A, D || Changes prop library's category |- | W, S || Scrolls through props in current category |- | LMB || Place current prop |- | V (hold) || LMB erases highlighted prop |- | Q,E || Rotate prop left and right |- | Space (hold) || Speed up rotation |- | Y,G,H,J || Stretch prop |- | T || Reset prop stretching |- | R || reset stretching, and rotation |- | Y, H || (on wire/tube props) increases or decreases prop's physics node count. Less means more taught, more means more loose. |- | X || Pause wire/tube physics |- | Tab+X+C || Clear all props |- | B || Click mouse left to set the highlighted prop as the currently selected prop. |- | L || Change layer |- | RMB || Cycle depth in current layer (10 sublevels). |- | Space + RMB || Cycle depth in current layer, reverse direction. |- | U-I-O-P (hold) || Freeform stretch by one of the corners (U - top right, I - bottom right, O - bottom left, and P - top left.) |- | K || resets freeform stretching. |- | N || Switches to editing properties menu of the prop. Things like forcing certain graffiti to be drawn instead of a random one. |- | M (hold) || LMB opens properties of an already placed prop instead of placing a prop (same menu as above) |- | Z || Changes prop color |- | F + LMB/RMB || Changes between prop variants. This only applies to certain props. |} |-|Environment Editor= {| class="wikitable" |+ Environment editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | L || Set water level to mouse pointer |- | F || Toggles between drawing water above the first layer or below it. |- | W || Toggle water on level |} </tabber> == Crash Avoidance and Editor Quirks == Due to the editor being extremely user unfriendly, you are likely to run into various crashes without warning. This is a list of various things to avoid doing. === Crashes: === Do not switch to editing applied effects in the Effects Editor when there are none. The switch will be invisible, and attempting to use the space bar to select something from there will crash the Level Editor. Some effects have very specific conditions and cause issues when rendering, Effects include: Thick Roots, and Shadow Plants. these ones can be okayed through until it renders.) Be sure to remove tiles from parts of a room that will be removed if you resize the room to cut those areas out, those tiles are still recorded, and will crash renders instantly. props are the exact same as above Never render with no cameras. It will crash. Always move the prop menu into an actual category when you open it, it keeps the last menu used, and crashes if you select any entry that is not a real prop. (EX: it will have the effects menu, or tile menu.) If you are using the Mirrored tile placer, in the geometry editor. Placing poles, with the other side of the mirrored brush being outside of the room, will crash the editor. === Quirks: === The main menu is a mess when you return from using the Light Editor or the Environment Editor. Just change to any other editor (geometry or tiles, and back to main menu) to clean it. This is not a crash, but will help prevent confusion if you know to expect this. To use the Move and Move Mirror tools in the editor, you must first select them, and then move your mouse outside of the room itself, before it will respond to your inputs. Usually you will only need to put your mouse over the editor, but in larger rooms, this is often an issue, as the room is "behind" the menu, and thus only changes tool selection. The editor still receives inputs if you only tab out using alt-tab. When viewing another window, it's important to always minimize the editor, because there are many things that can go wrong if you're randomly clicking in the editor. (Requires more confirmation) The screen during rendering should usually show the map being rendered, but it may not. In the task manager, The Rain World Editor is under the tab Adobe Projector. Sometimes the reason it is not showing is a second application called "Print driver host for applications". Closing the application seems to fix the issue. The window for the application may be too big to fit on screen, and cannot be fixed since reaching the top bar or right clicking cannot be accessed to move the window. === Demo and Tutorial Videos === Region Developer Kaeporo created a tutorial for creating levels in and out of the level editor: {{#ev:youtube|YQ0DO-fmPCE|||||urlargs=""}} Mod community member Sacretis also put together a demonstration video, this time covering the creation of a room from scratch to visual polish (massively sped up for the sake of time): {{#ev:youtube|sEE3X1izaJA|||||urlargs=""}} b2a3cd6b98acaa9253c0ba90a927c75b76c39170 546 522 2023-09-14T12:32:51Z Theescape 203 Grammar, spelling, formatting fixes wikitext text/x-wiki The Level Editor is an application created by the Rain World developers in order to create new in-game rooms and edit existing ones. There are two officially released versions of the editor: the [https://steamcommunity.com/app/312520/discussions/0/1700541698703118028/ original] editor used to create the base game, and the [https://store.steampowered.com/news/app/312520/view/3671033323706467799 updated] editor used for the Downpour expansion. The editor functions by using specially formatted spritesheets and a number of programmed effects and outputs PNG files that the engine interprets in 3D (as well as an accompanying text file which contains collision and gameplay info). == The Official Level Editor == [[File:editorFront.png|400px|thumb|right]] === Basic Features Overview === Once you've opened/created a level, you are presented with the preview screen of the level, although this preview needs to be manually updated using the "update preview" button whenever changes are made to the level for it to remain accurate. The buttons can be used to navigate between the different editors, load a new level, or save/rename your current level and export it's geometry data for use in-game. Pressing "1" will bring you back to this screen. It's often best to start by modifying the dimensions of the room to your liking using the level size button before beginning to edit. You can change this at any time, but because you set the dimensions manually rather than visually, making changes later is more difficult and poses the risk of accidentally deleting a portion of your room if you aren't careful. From the dashboard you can switch to the Geometry Editor - used for defining the level geometry and collision, the Tile Editor (for customizing the tiles and assets that make up the geometry created in the geometry editor), the Effects Editor (for adding procedural effects like erosion or slime, as well as things like plants or chains), the Light Editor - for painting light and shadow, or the Prop Editor (for adding additional hand placed props and decals like graffiti). === Controls Overview === ==== View controls (numpad): ==== These are used for every editor view, except for the Camera and Environment editor, to scroll around the screen. Note that numlock must be enabled for these controls to have any effect. {| class="wikitable" |+ |- ! Key(s) !! Function |- | 8, 2, 4, 6 || Moves view |- | 1 (hold) || Increases view scroll speed. |- | 3 (hold) || Increases view scroll speed even more. |- | 9 (hold) || Allow the view to move outside the boundaries of the level. |} ==== Menu keybinds (Number row): ==== These act as hotkeys to quickly switch between different editor views. These can be used in any editor view as well. {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | 1 || Main menu |- | 2 || Geometry |- | 3 || Tiles |- | 4 || Cameras |- | 5 || Light |- | 6 || Room size |} === Level Settings === ==== Level Size ==== Allows you to set the level's dimensions. You can set the entire level size, and border tiles. Border tiles are padding around the room, mainly for resolutions that are larger than 4:3 (It is recommended to not go under the default's numbers, as this will cause the final render to be cut off.) To calculate the size your level needs to be, you can use the following formula:<br> <pre> Width = 52 * Screens + 20 Height = 40 * Screens + 3 </pre> {| class="wikitable" |+ Example Level Sizes |- ! Screens (WxH) !! Width !! Height |- | 1x1 || 72 || 43 |- | 1x2 || 72 || 83 |- | 1x3 || 72 || 123 |- | 1x4 || 72 || 163 |- | 1x5 || 72 || 203 |- | 1x6 || 72 || 243 |- | 2x1 || 124 || 43 |- | 3x1 || 176 || 43 |- | 4x1 || 228 || 43 |- | 5x1 || 280 || 43 |- | 6x1 || 332 || 43 |} ==== Default Medium ==== This determines whether you can fall outside of the level or not, but death pits still work the same either way. ==== Light Type ==== The light type can either be set to '''ON''' which will use what you have done in the Light Editor, or '''OFF''' which paints everything in shadow. ==== Seed ==== This is the arrow on the fourth row of bars, which determines what seed the level will use. The seed determines random tile and prop placement, along with how effects are generated. === Rendering === ==== Prioritize Cam ==== Allows you to choose a specific camera to render first. ==== Text Output ==== This outputs a .txt file of the level's geometry and collision, usable in-game. ==== Render Level ==== Renders the room's screens. When a screen is fully rendered it will be in the Levels folder even if the rest of the level hasn't finished rendering. ==== Mass Render ==== Renders every level in the selected folder. === Editors === <tabber> |-|Geometry Editor= == Geometry Editor == [[File: geoEditor.png|400px|thumb|right]] In the Geometry Editor, you can define the elements and collision information of your room, including poles, shortcuts, room entrances, creature dens, garbage worms, room connections, and a number of other gameplay-relevant elements. {| class="wikitable" |+ Geometry editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | Arrow keys || Primary cursor to scroll through the toolbox. If the mouse is over the toolbox, the mouse moves the toolbox's cursor instead. |- | Mouse || Primary cursor movement. |- | LMB || Primary cursor: use current tool. |- | Q (hold) || Use secondary cursor on the toolbox. |- | E,S,D,F || Secondary cursor movement. |- | W || Secondary cursor use current tool. |} As an experimental feature, the developers implemented a second grey cursor with an alternate control scheme to allow two users to edit a room simultaneously. While this likely ended up being a seldom-used feature, it is still implemented and usable in the current editor. == Toolbox == {| class="wikitable" |+ Level Editor Geography Tools |- ! Tool !! Function |- | Inverse || Flips the currently selected tile between walls, and air. |- | Paint Walls || Paints solid tiles. |- | Paint Air || Paints non-solid tiles. |- | Make Slope || Paints a slope. Slopes can only be placed inside corners, or at the edges of larger solids. |- | Make Floor || Paints thin platforms that entities can stand on. The player can fall through these by pressing "down". |- | Rect Wall || Paints solid tiles in a rectangle. Click two points to set the rectangle's dimensions and paint. |- | Rect Air || Same as above, except for non-solid tiles. |- | Worm Grass || Place above solid ground to spawn worm grass tendrils. The number of adjacent Worm Grass tiles determines the height of the grass. |- | Crack Terrain || Renders as a roughly cracked fissure through the material painted on it in the tile editor. Slugcat can crawl through these tunnels. An example of this in the vanilla game is in the Depths, where there are fissures to travel beneath certain stone statues. |- | Horizontal Beam || A pole that creatures can climb on. Slugcat can only climb these on layer 1. |- | Vertical Beam || Same as above, except in the other direction. |- | Glass Wall || Paints invisible walls. |- | Waterfall || Will cause a waterfall to appear in game, with this tile at the top of it. |} {| class="wikitable" |+ Level Editor Item and Batfly Tools |- ! Tool !! Function |- | Place Rock || 60% chance a Rock will spawn at this location. |- | Place Spear || 60% chance a Spear will spawn at this location. |- | Spawn Fly || Does nothing. |- | Forbid Fly Chains || Prevents batflies from hanging together in specific locations. |- | Hive || Places a batfly hive. Batflies use these to quickly travel between hives. |} [[File: shortcuts_yes.png|270px|thumb|Examples of working shortcuts]] [[File: shortcuts_no.png|270px|right|thumb|Examples of broken shortcuts]] {| class="wikitable" |+ Level Editor Shortcut Tools |- ! Tool !! Function |- | Short Cut Entrance || Places the entrance of a short cut into the room, these must be fully surrounded by ground except from the entrance side and the exit will always be aiming in the opposite direction of the entrance. When placed on the floor, both players and creatures will fall into them, so its advised to always put a platform in the entrance instead of air in these cases. |- | Short Cut || Places a short cut's travel dot. These can connect two short cut entrances together or connect into a specific entrance or den variation. They can also have no destination, in which case the shortcut entrance will simply be blocked. Short cut dots can cross with each other in a + pattern and each path will always continue forwards. |- | Dragon Den || Places a creature den. These hold the creature assigned to that den in the region's World File. Creatures can move to the closest den if they can't return to their own. |- | Entrance || Used to connect with another room. These can be used by Slugcat and most creatures to travel across a region. The two rooms connected by this entrance are determined by the region's World File. |- | Scavenger Hole || Allows scavengers to spawn or travel to this room as they wander through a region. Since scavengers use offscreen dens, all Scavenger Holes will share the same pool of scavengers. |- | Whack-A-Mole-Hole || Allows creatures to travel around a room by "teleporting" between these holes. There is no limit to how many holes can be placed in the same room and they are all connected with each other. When a creature enters one of these holes and selects a new destination there is a short period of time in which the shortcut segment glows, so they are often used without Short Cut dots. |- | "G" Garbage Worm den || Unlike the rest of dens, its not attached to a short cut entrance. Instead they are simply placed in the ground tile where we want the Garbage Worm to spawn. |} A short cut dot is not required between the short cut's entrance and the den or door it's connecting to. However, the shortcut must show as an arrow toward the den or door for the link to it to be proper. Short cuts and their connections to the various kinds of entrances in Rain World have specific needs! Improperly making the short cut can lead to crashes, or odd behavior in game. A list of common mistakes include: * Short cuts going outside of the level bounds, anything out of the white frame won't be loaded in game. * Short cut entrances placed directly on the surface. * Short cut entrances with short cut dots on any side which isn't the opposite to the entrance. * Creature dens or room entrances randomly floating in the room disconnected from everything. * Placing Garbage Worm dens connected to an entrance like the other dens. {| class="wikitable" |+ Level Editor Layer and Misc Tools |- ! Tool !! Function |- | Copy Backwards || Copies a rectangle of tiles on the current layer to the next layer. This does not wrap around back to layer 1 if you are on layer 3. |- | Work Layer || Changes layers from 1 to 3 and then back to 1. |- | Clear All || Selects a rectangle that resets all tiles inside it, on all layers, back to open air. |- | Toggle Mirror || Turns on and off a mirror tile painting mode. What you do on one side of the mirror will be copied on the other. |- | Move Mirror || Allows you to move the location of the Mirror. |- | Move Level || Moves the whole level in a certain direction. Place the mouse cursor outside the level, then use the arrow keys to move the level in the direction you want. It will not work if your mouse is inside the level as using the arrow keys will swap to another tool. |- | Empty || Does nothing. Good to set as your tool if you have to tab out, as it does nothing. |} Rain World levels consist of 3 layers, each representing a different depth. This layer info is represented visually through the color of tiles, and you can switch between editing on different layers with the work layer tool in the bottom left of the tool panel. Layer 1 draws in full black, layer 2 draws in green, and layer 3 draws in red. These colors will blend if multiple layers are drawn on top of each other. Layer 1 is the foreground, and any filled tiles on this layer will have collision. This is the base layer you define for the sake of gameplay, as any air here is space you can traverse. Layer 2 is the midground, which you can imagine as the back wall of your room. Wall climbing creatures also interact with this. Layer 3 is the extreme background, behind the back wall of the room (for placing distant objects or giving the room a section of open sky). Nothing interacts with this at all. Note: The tile editor defines the visual tiles and props that make up this geometry, so in order to place solid objects in the tile editor (on any layer), those tiles need to be filled here in the geometry editor. Even though the mid-ground and background do not provide any collision geometry, in order to place solid props on those layers the tiles need to be filled here in the geometry editor. Similarly, some props can only be placed on air on the layers (like fences). === Tips and Tricks === - Many of the gameplay features require that they be placed within the margins of your room (represented by the white border). An entrance or creature den placed outside of your margins will render your room impossible to enter at best, and crash the game at worst. Short Cut Entrances and Short Cuts can be placed outside the level boundary just fine, however. - Border tiles are tiles that can't be interacted with, and are there for looks only. The room will copy the last tile from the border forever in that direction, so be careful with your geometry or you'll be able to walk out of bounds through "solid" walls or stand in the air. - Because the toolbox cursor wraps around from top to bottom and left to right, when editing the base geometry (walls and air) it's faster to use the arrow keys to go up to reach the work layer tool to swap layers than to cycle through the whole list to reach them. Also, the rectangular wall and air tools will let you edit large chunks of your level much faster than going tile by tile. - Because the layers move with a parallax effect, it's often necessary to extend elements on your background layer behind your other layers, otherwise the camera angle will sometimes let you see a gap to the left or right of a background wall and the layer in front of it (for example). It can be extended just a few tiles, unless you have tiles in front that are transparent and reveal behind it. |-|Tile Editor= {| class="wikitable" |+ Tile editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A-D || Flip\scroll through tile categories |- | W-S || Select tile in current category |- | LMB || Place tile under cursor |- | RMB || Erase tile under cursor |- | F (hold) || Use a 3x3 brush for materials |- | V (hold) || Use a 5x5 brush for materials |- | Tab+x+c || Clears all tiles |- | L || Change active layer (1, 2, 3, loop back to 1) |- | E || Set default material of the room to the currently selected material |- | F (hold) || Force places selected tile, ignores geometry and erases colliding tiles |- | G (hold) || Enables force placing selected tile (forcing appropriate geometry for the tile, erasing colliding tiles) |- | Q || "Eyedropper" (selects tile/material hovered over) |} |-|Effect Editor= {| class="wikitable" |+ Effect library keybinds |- ! '''Key(s)''' !! '''Function''' |- | A, D || Select effect category |- | W, S || Select effect in current category |- | E || Switches to editing applied effects |- | Space || Adds selected effect to the stack |} {| class="wikitable" |+ Applied effect keybinds |- ! '''Key(s)''' !! '''Function''' |- | W,S || Scroll through the effect stack |- | N || Switch to effect library |- | Space || Edit selected effect in the stack |} {| class="wikitable" |+ Effect editing keybinds |- ! '''Key(s)''' !! '''Function''' |- | A, D || Scroll through options in the effect's menu |- | W, S || Changes the current effect's menu |- | Space || Activates selected option in the effect's menu |- | LMB || Paints effect in the level |- | RMB || Erases effect in the level |- | R || Brush size up |- | F || Brush size down |- | E || Switch to effect stack |- | N || Switch to effect library |} |-|Camera Editor= {| class="wikitable |+ Camera editing keybinds |- ! '''Key(s)''' !! '''Function''' |- | N || New camera; automatically held by mouse |- | E || Grab a camera if none is currently held |- | D || Delete held camera |- | P || Place held camera |} Note: A maximum of 20 Cameras can be placed per level. |-|Light editor= {| class="wikitable" |+ Light editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | W, A, S, D || Scale current light shape |- | Q, E || Rotate current light shape |- | Z || Toggle between drawing and erasing light |- | LMB || Paint light |- | RMB (hold) || Rotate light shape in direction of mouse (does not paint) |- | R, F || Scroll through light shape library |- | J, L || Change angle of light source |- | I, K || Change distance of light source |} |-|Prop Editor= {| class="wikitable" |+ Prop editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | A, D || Changes prop library's category |- | W, S || Scrolls through props in current category |- | LMB || Place current prop |- | V (hold) || LMB erases highlighted prop |- | Q, E || Rotate prop left and right |- | Space (hold) || Speed up rotation |- | Y, G, H, J || Stretch prop |- | T || Reset prop stretching |- | R || Reset stretching and rotation |- | Y, H || (on wire/tube props) Increases or decreases prop's physics node count. Lower numbers mean more taut, and higher numbers mean more loose. |- | X || Pause wire/tube physics |- | Tab+X+C || Clear all props |- | B || Click mouse left to set the highlighted prop as the currently selected prop. |- | L || Change layer |- | RMB || Cycle depth in current layer (10 sublevels). |- | Space + RMB || Cycle depth in current layer, reverse direction. |- | U, I, O, P (hold) || Freeform stretch by one of the corners (U - top right, I - bottom right, O - bottom left, and P - top left.) |- | K || Resets freeform stretching. |- | N || Switches to editing properties menu of the prop. Things like forcing certain graffiti to be drawn instead of a random one. |- | M (hold) || LMB opens properties of an already placed prop instead of placing a prop (same menu as above) |- | Z || Changes prop color |- | F + LMB/RMB || Changes between prop variants. This only applies to certain props. |} |-|Environment Editor= {| class="wikitable" |+ Environment editor keybinds |- ! '''Key(s)''' !! '''Function''' |- | L || Set water level to mouse pointer |- | F || Toggles between drawing water above the first layer or below it. |- | W || Toggle water on level |} </tabber> == Crash Avoidance and Editor Quirks == Due to the editor being extremely user unfriendly, you are likely to run into various crashes without warning. This is a list of various things to avoid doing. === Crashes === * Do not switch to editing applied effects in the Effects Editor when there are none. The switch will be invisible, and attempting to use the space bar to select something from there will crash the Level Editor. * Some effects have very specific conditions and cause issues when rendering, Effects include: Thick Roots, and Shadow Plants. these ones can be okayed through until it renders.) * Be sure to remove tiles/props from parts of a room that will be removed if you resize the room to cut those areas out. Those tiles/props still exist, and will crash renders instantly. * Attempting to render with no cameras will trigger a crash. * Always move the prop menu into an actual category when you open it, as it keeps the last menu used and crashes if you select any entry that is not a real prop. (EX: it will have the effects menu, or tile menu.) * If you are using the geometry editor's Mirrored tile placer: Placing poles with the other side of the mirrored brush being outside of the room will crash the editor. === Quirks === * The main menu is a mess when you return from using the Light Editor or the Environment Editor. Just change to any other editor (geometry or tiles, and back to main menu) to clean it. This is not a crash, but will help prevent confusion if you know to expect this. * To use the Move and Move Mirror tools in the editor, you must first select them, and then move your mouse outside of the room itself, before it will respond to your inputs. Usually you will only need to put your mouse over the editor, but in larger rooms, this is often an issue, as the room is "behind" the menu, and thus only changes tool selection. * The editor still receives inputs if you only tab out using alt-tab. When viewing another window, it's important to always minimize the editor, because there are many things that can go wrong if you're randomly clicking in the editor. * (Requires more confirmation) The screen during rendering should usually show the map being rendered, but it may not. In the task manager, The Rain World Editor is under the tab Adobe Projector. Sometimes the reason it is not showing is a second application called "Print driver host for applications". Closing the application seems to fix the issue. * The window for the application may be too big to fit on screen, and cannot be fixed since reaching the top bar or right clicking cannot be accessed to move the window. === Demo and Tutorial Videos === Region Developer Kaeporo created a tutorial for creating levels in and out of the level editor: {{#ev:youtube|YQ0DO-fmPCE|||||urlargs=""}} Mod community member Sacretis also put together a demonstration video, this time covering the creation of a room from scratch to visual polish (massively sped up for the sake of time): {{#ev:youtube|sEE3X1izaJA|||||urlargs=""}} 998fef24e1cbf84ad4784c58091569dc7da0c8c0 Creating Custom Tiles and Props 0 202 517 2023-06-25T16:48:36Z INVADA 173 Created page with " == Basic Requirements == In order to create custom tile and prop assets you first need to install any version of the RW level editor, and any type of drawing program that supports pixel art (Do NOT use MS Paint) Open the editor file and navigate to the "graphics" folder, this is where the editor reads tile graphics from." wikitext text/x-wiki == Basic Requirements == In order to create custom tile and prop assets you first need to install any version of the RW level editor, and any type of drawing program that supports pixel art (Do NOT use MS Paint) Open the editor file and navigate to the "graphics" folder, this is where the editor reads tile graphics from. e44dac2005a67915252043db436054d3a8d1c549 519 517 2023-06-25T17:33:07Z INVADA 173 A page showing how to make custom tiles and props, most of this information is taken from M4rbleL1ne's github page. wikitext text/x-wiki == Basic Requirements == In order to create custom tile and prop assets you first need to install any version of the RW level editor, and any type of drawing program that supports pixel art (Do NOT use MS Paint) == Tiles == Tiles follow a 20x20 pixel grid while the tile editor preview follows a 16x16 grid. Blue is the colour of the layer when lit up , green is the normal colour of the layer, and red is the shaded colour of the layer. <gallery> [[File:Crushertileexample.png|frameless|center|A example of a tile setup]] </gallery> , a unmodified Slugcat is about 3 tiles tall standing and 1 tile tall when crouching, keep this in mind when designing tiles to make sure they are sized properly. the top row of pixels NEEDS to be pure white with one black pixel in the top left to display correctly. Open the editor file and navigate to the "graphics" folder, this is where the editor reads tile graphics from. == Props == == Palettes == == Decals == Place your desired image in the "Decals" folder inside of "Rainworld > StreamingAssets > Decals" Open up dev tools, navigate to the "CustomDecal" object and then select the name of your decal and place it. Now either die or hibernate a cycle to save your new decal. If you left your decal at the default size you will most likely need to make it bigger to see it properly. d721ad0e8965493d494203b2d32ee35c2a6899c8 520 519 2023-06-25T18:02:34Z INVADA 173 wikitext text/x-wiki == Requirements == In order to create custom tile and prop assets you first need to install any version of the RW level editor, and any type of drawing program that supports pixel art (Do NOT use MS Paint) == Tiles == The level editor stores tile graphics in the "Graphics" folder and tile collision in the Tiles follow a 20x20 pixel grid while the tile editor preview at the bottom follows a 16x16 grid. Blue is the color of the layer when lit up, green is the normal color of the layer, and red is the shaded color of the layer. the top row of pixels NEEDS to be pure white with one black pixel in the top left to display correctly. [[File:Crushertileexample.png|frame|right|A example of a tile setup]] , a unmodified Slugcat is about 3 tiles tall standing and 1 tile tall when crouching, keep this in mind when designing tiles to make sure they are sized properly. Open the editor file and navigate to the "graphics" folder, this is where the editor reads tile graphics from. == Props == The level editor stores tile graphics in the "Props " folder and prop details in the init == Palettes == == Decals == Place your desired image in the "Decals" folder inside of "Rainworld > StreamingAssets > Decals" Open up dev tools, navigate to the "CustomDecal" object and then select the name of your decal and place it. Now either die or hibernate a cycle to save your new decal. If you left your decal at the default size you will most likely need to make it bigger to see it properly. 7316f0116c39f21fb4a88e8660ea8512473ab9f3 523 520 2023-07-04T20:40:58Z INVADA 173 /* Tiles */ wikitext text/x-wiki == Requirements == In order to create custom tile and prop assets you first need to install any version of the RW level editor, and any type of drawing program that supports pixel art (Do NOT use MS Paint) == Tiles == The level editor stores tile graphics in the "Graphics" folder and tile collision in the Tiles follow a 20x20 pixel grid while the tile editor preview at the bottom follows a 16x16 grid. Blue is the color of the layer when lit up, green is the normal color of the layer, and red is the shaded color of the layer. the top row of pixels NEEDS to be pure white with one black pixel in the top left to display correctly. Keep in mind a unmodified Slugcat is about 3 tiles tall standing and 1 tile tall when crouching, keep this in mind when designing tiles to make sure they are sized properly. Use the specs editor or fill the specs out manually, input the name of your tile and its specs and properties into the init file for tiles and then place the finished tile graphics in the editors "graphics" folder. [[File:Crushertileexample.png|frame|right|A example of a proper tile setup]] == Props == The level editor stores tile graphics in the "Props " folder and prop details in the init == Palettes == == Decals == Place your desired image in the "Decals" folder inside of "Rainworld > StreamingAssets > Decals" Open up dev tools, navigate to the "CustomDecal" object and then select the name of your decal and place it. Now either die or hibernate a cycle to save your new decal. If you left your decal at the default size you will most likely need to make it bigger to see it properly. bd44b47bbec52de794ad3d629ae0d6a18fbe26a5 526 523 2023-07-04T20:46:28Z INVADA 173 wikitext text/x-wiki {{todo}} == Requirements == In order to create custom tile and prop assets you first need to install any version of the RW level editor, and any type of drawing program that supports pixel art (Do NOT use MS Paint) == Tiles == The level editor stores tile graphics in the "Graphics" folder and tile collision in the Tiles follow a 20x20 pixel grid while the tile editor preview at the bottom follows a 16x16 grid. Blue is the color of the layer when lit up, green is the normal color of the layer, and red is the shaded color of the layer. the top row of pixels NEEDS to be pure white with one black pixel in the top left to display correctly. Keep in mind a unmodified Slugcat is about 3 tiles tall standing and 1 tile tall when crouching, keep this in mind when designing tiles to make sure they are sized properly. Use the specs editor or fill the specs out manually, input the name of your tile and its specs and properties into the init file for tiles and then place the finished tile graphics in the editors "graphics" folder. [[File:Crushertileexample.png|frame|right|A example of a proper tile setup]] == Props == The level editor stores tile graphics in the "Props " folder and prop details in the init == Palettes == == Decals == Place your desired image in the "Decals" folder inside of "Rainworld > StreamingAssets > Decals" Open up dev tools, navigate to the "CustomDecal" object and then select the name of your decal and place it. Now either die or hibernate a cycle to save your new decal. If you left your decal at the default size you will most likely need to make it bigger to see it properly. d38c33207d24e5ac9675f645ebfdd30192f8d9fd 527 526 2023-07-04T20:49:44Z INVADA 173 /* Decals */ wikitext text/x-wiki {{todo}} == Requirements == In order to create custom tile and prop assets you first need to install any version of the RW level editor, and any type of drawing program that supports pixel art (Do NOT use MS Paint) == Tiles == The level editor stores tile graphics in the "Graphics" folder and tile collision in the Tiles follow a 20x20 pixel grid while the tile editor preview at the bottom follows a 16x16 grid. Blue is the color of the layer when lit up, green is the normal color of the layer, and red is the shaded color of the layer. the top row of pixels NEEDS to be pure white with one black pixel in the top left to display correctly. Keep in mind a unmodified Slugcat is about 3 tiles tall standing and 1 tile tall when crouching, keep this in mind when designing tiles to make sure they are sized properly. Use the specs editor or fill the specs out manually, input the name of your tile and its specs and properties into the init file for tiles and then place the finished tile graphics in the editors "graphics" folder. [[File:Crushertileexample.png|frame|right|A example of a proper tile setup]] == Props == The level editor stores tile graphics in the "Props " folder and prop details in the init == Palettes == == Decals == In order to create a new decal folders inside of "Rainworld > StreamingAssets > Decals" Open up dev tools, navigate to the "CustomDecal" object and then select the name of your decal and place it. Now either die or hibernate a cycle to save your new decal. If you left your decal at the default size you will most likely need to make it bigger to see it properly. 389b7bc59fcdce50a29f1ae3b9a778179179565d 547 527 2023-09-15T19:59:05Z Dakras 6 /* Tiles */ Slug is 2 tiles, not 3. wikitext text/x-wiki {{todo}} == Requirements == In order to create custom tile and prop assets you first need to install any version of the RW level editor, and any type of drawing program that supports pixel art (Do NOT use MS Paint) == Tiles == The level editor stores tile graphics in the "Graphics" folder and tile collision in the Tiles follow a 20x20 pixel grid while the tile editor preview at the bottom follows a 16x16 grid. Blue is the color of the layer when lit up, green is the normal color of the layer, and red is the shaded color of the layer. the top row of pixels NEEDS to be pure white with one black pixel in the top left to display correctly. Keep in mind a unmodified Slugcat is about 2 tiles tall standing and 1 tile tall when crouching, keep this in mind when designing tiles to make sure they are sized properly. Use the specs editor or fill the specs out manually, input the name of your tile and its specs and properties into the init file for tiles and then place the finished tile graphics in the editors "graphics" folder. [[File:Crushertileexample.png|frame|right|A example of a proper tile setup]] == Props == The level editor stores tile graphics in the "Props " folder and prop details in the init == Palettes == == Decals == In order to create a new decal folders inside of "Rainworld > StreamingAssets > Decals" Open up dev tools, navigate to the "CustomDecal" object and then select the name of your decal and place it. Now either die or hibernate a cycle to save your new decal. If you left your decal at the default size you will most likely need to make it bigger to see it properly. 880422b2123c8811eafb7460dfbc23c23cd2eb1b File:Crushertileexample.png 6 203 518 2023-06-25T17:31:41Z INVADA 173 wikitext text/x-wiki The Crusher tile from Rainworld's assets, very green 1d572d066f65bb0b0fefcde5a804eb254e7983c6 Logs 0 185 524 438 2023-07-04T20:43:38Z INVADA 173 wikitext text/x-wiki {{todo|target=page}} Logs are used to keep track of why your mod might have crashed Rainworld, logs are exceptionally helpful for finding bugs and crashes. {| class="wikitable" |+ Rain World generates the following log files |- ! File !! Function !! Frequently useful |- | <code>exceptionLog.txt</code> || vanilla errors and unhandled mod errors || Yes |- | <code>consoleLog.txt</code> || vanilla log calls || No |- | <code>BepInEx/LogOutput.log</code> || logs from [[BepInPlugins]] || Yes |} 83045759f3fb187f2bc1fb1ff4ec6e65ba9e68de 525 524 2023-07-04T20:44:01Z INVADA 173 wikitext text/x-wiki {{todo|target=page}} Logs are used to keep track of why your mod crashed Rainworld, logs are exceptionally helpful for finding bugs and crashes. {| class="wikitable" |+ Rain World generates the following log files |- ! File !! Function !! Frequently useful |- | <code>exceptionLog.txt</code> || vanilla errors and unhandled mod errors || Yes |- | <code>consoleLog.txt</code> || vanilla log calls || No |- | <code>BepInEx/LogOutput.log</code> || logs from [[BepInPlugins]] || Yes |} 0e1fbbc31e5356d05349fef776ea0d30f9ebb550 Rain World Code Structure/World 0 204 528 2023-07-19T18:19:11Z Thalber 3 init wikitext text/x-wiki {{todo|target=article}} '''World''' class represents state of a single region being played. It contains all [[../Rooms|rooms]], [[../AbstractWorldEntity|entities]] and region-wide processes and the like, and passes lifecycle (Update, etc) calls down to them. A world can be single-room when the game is in arena mode. World class ''does not fully populate itself from the savedata''. World data is partially processed by [[../WorldLoader|WorldLoader]] (''after'' the World object is constructed, so there are points in World's lifecycle where it's blank and some members are uninitialized). == Notable members == {| class="wikitable sortable" |+ |- ! Name !! Kind !! Description |- | abstractRooms || Field || An array of all rooms within this region. |- | activeRooms || Field || A list of all rooms in this region that are currently realized. |- | brokenShelters || Field || An array of booleans, each one corresponding to a shelter with the same index, telling whether that shelter is broken (false is working, true is broken) |- | DisabledMapRooms || Field || A list of rooms that are not shown on the maps (not the same thing as rooms whose entrances are hidden with a placed object) |- | gates || Field || Room indices of all gates. |- | lineages || Field || An array containing all lineage spawners of the world. |- | loadingRooms || Field || A list of RoomPreparer objects representing rooms that are currently in the process of being realized. |- | name || Field || Current region's acronym (SU for Outskirts, HI for Industrial, etc) |- | offScreenDen || Field || A special abstract room that acts as a hub for specific creatures, such as Scavengers, Vultures, and Miros birds (generally, any creature that is not quantified and also is not bound to a specific room by spawns) |- | rainCycle || Field || Object holding information about current state of world rain (whether it hit or not, does it currently cut off music) |- | region || Field || Object holding some extra data about current region's layout (mostly data defined in region properties file, such as subregions or scav spawn chances, DLL eye colors, number of allowed overseers{{Cn}}) |- | shelters || Field || Array of room indices of all rooms marked as shelters |- | singleRoomWorld || Field || Whether the world is an arena world |- | spawners || Field || Array of spawners - objects holding information about creature spawns, recent deaths and respawn times. Also includes lineages. |- | swarmRooms || Field || Array of room indices of rooms marked with SWARMROOM tag in world_xx file. |- | worldProcesses || Field || List of "world processes" - special objects that are attached to current world and receive updates alongside it. This includes region-wide coordinators, like ScavengerWorldAI and FliesWorldAI. |- | firstRoomIndex || Property || Global index of the first room in the region. |- | game || Property || RainWorldGame this world belongs to |- | RegionState || Property || Object containing save data about the region (current living creatures, saved objects, consumed consumables, etc). More detail should be in [[../Save_Data|Savedata page]]. |- | AddWorldProcess || Method || Adds a world process to the world's process list. |- | GetAbstractRoom (multiple overloads) || Method || Returns an abstract room queried by WorldCoordinate, global index or name. When querying by name, "OFFSCREEN" corresponds to offscreen den. Returns null if room was not found. |- |} 67c358cd3b77b2c648df6fce4553314c5d6e451f Rain World Code Structure/LOD 0 192 529 482 2023-07-19T18:24:21Z Thalber 3 wikitext text/x-wiki {{todo|target=page}} Rain World uses two LOD ([https://en.wikipedia.org/wiki/Level_of_detail_(computer_graphics) Level Of Detail]) modes for entities in main loop: * Realized - high detail, updates every frame, physical interactions are fully rendered. Used in rooms close to player. * Abstract - low detail, each entity receives updates every several frames, physics interactions and detailed creature movements are replaced with simpler probabilistic interaction models (can be thought of as dice rolls). Default state. LOD level is selected on per-room basis, and is passed down on all entities in room. When in a realized room, abstract LOD entities (base class for these is (technically) AbstractWorldEntity and (practically) AbstractPhysicalObject) persist, but a realized version is attached to them until they abstractize again. All data not explicitly stored in abstract object is lost when an entity abstracts. This affects, for example, wolf spider revive mechanic: wolf spiders store a representation of one other spider they are willing to revive when they have body contact (<code>reviveBuddy</code> field in <code>BigSpiderAI</code>), and forget it when they leave realized space. For more details about Room and AbstractRoom objects in particular, see [[../Rooms|Rooms]]. == Abstract layer == Rooms are <code>AbstractRoom</code>, and all entities are <code>AbstractWorldEntity</code>. '''AbstractWorldEntity'''`s one child class is '''AbstractPhysicalObject''', and AbstractWorldEntity is never instantiated in vanilla (so in practice everything in abstract world is an AbstractPhysicalObject). For more info on inheritance hierarchy, see [[../AbstractWorldEntity|AbstractWorldEntity]]. == Realized layer == Rooms are <code>Room</code> (always attached to an instance of AbstractRoom), basic entities are <code>UpdatableAndDeletable</code>, AbstractPhysicalObject realized versions are <code>PhysicalObject</code>. Unlike with abstract LOD, '''UpdatableAndDeletable''' has children that are not '''PhysicalObject'''s (cosmetic sprites, background elements, etc). UpdatableAndDeletable may be shortened to UAD in this section. === UpdatableAndDeletable === The most basic room entity. As the name suggests, can be added to a room, updated inside a room and deleted from a room. See [[../UpdatableAndDeletable|UpdatableAndDeletable]] for details. === PhysicalObject === Realized LOD versions of '''AbstractPhysicalObject'''s. Everything that can be whacked and tossed. See [[../PhysicalObject_Basics|PhysicalObject Basics]] for details. b1e4b3172224fb6f5917e0b43b2e7a9767442fe2 530 529 2023-07-19T19:07:50Z Thalber 3 wikitext text/x-wiki {{todo|target=page}} Rain World uses two LOD ([https://en.wikipedia.org/wiki/Level_of_detail_(computer_graphics) Level Of Detail]) modes for entities in main loop: * Realized - high detail, updates every frame, physical interactions are fully rendered. Used in rooms close to player. * Abstract - low detail, each entity receives updates every several frames, physics interactions and detailed creature movements are replaced with simpler probabilistic interaction models (can be thought of as dice rolls). Default state. LOD level is selected on per-room basis, and is passed down on all entities in room. When in a realized room, abstract LOD entities (base class for these is (technically) AbstractWorldEntity and (practically) AbstractPhysicalObject) persist, but a realized version is attached to them until they abstractize again. All data not explicitly stored in abstract object is lost when an entity abstracts. This affects, for example, wolf spider revive mechanic: wolf spiders store a representation of one other spider they are willing to revive when they have body contact (<code>reviveBuddy</code> field in <code>BigSpiderAI</code>), and forget it when they leave realized space. For more details about Room and AbstractRoom objects in particular, see [[../Rooms|Rooms]]. == Abstract layer == Rooms are <code>AbstractRoom</code>, and all entities are <code>AbstractWorldEntity</code>. '''AbstractWorldEntity'''`s one child class is '''AbstractPhysicalObject''', and AbstractWorldEntity is never instantiated in vanilla (so in practice everything in abstract world is an AbstractPhysicalObject). For more info on inheritance hierarchy, see [[../AbstractWorldEntity|AbstractWorldEntity]]. == Realized layer == Rooms are <code>Room</code> (always attached to an instance of AbstractRoom), basic entities are <code>UpdatableAndDeletable</code>, AbstractPhysicalObject realized versions are <code>PhysicalObject</code>. Unlike with abstract LOD, '''UpdatableAndDeletable''' has children that are not '''PhysicalObject'''s (cosmetic sprites, background elements, etc). UpdatableAndDeletable may be shortened to UAD in this section. === UpdatableAndDeletable === The most basic room entity. As the name suggests, can be added to a room, updated inside a room and deleted from a room. See [[../UpdatableAndDeletable|UpdatableAndDeletable]] for details. === PhysicalObject === Realized LOD versions of '''PhysicalObject'''s. Everything that can be whacked and tossed. See [[../PhysicalObject_Basics|PhysicalObject Basics]] for details. 9d91b64d00173405172f49891e4f59e0e19a1606 Rain World Code Structure/Rooms 0 205 531 2023-07-19T19:08:22Z Thalber 3 init wikitext text/x-wiki '''Rooms''' are singular levels of the game, building blocks of a [[../World|world]]. Rooms exist in two [[../LOD|LOD]] levels: Abstract and Realized. == Abstract == Class for rooms in abstract LOD is AbstractRoom. === Notable members === {| class="wikitable sortable" |+ |- ! Name !! Kind !! Description |- | connections || Field || Indices of rooms this room is connected to{{Cn}}. |- | dens || Field || Number of creature dens (unrelated to shelters) in room{{Cn}}. |- | creatures || Field || List of all creatures in current room. |- | entities || Field || List of all entities occupying current room's free space. Includes creatures. |- | entitiesInDens || Field || List of all entities occupying dens in current room. |- | exits || Field || Number of exits. |- | firstTimeRealized || Field || Whether next realization will be the first in current session. |- | gateIndex || Field || Index of the current room in this world's gate array, -1 if not a gate. |- | shelterIndex || Field || Index of the current room in this world's shelter array, -1 if not a shelter. |- | swarmRoomIndex || Property || Index of the current room in this world's swarmRoom array, -1 if not a swarmroom. |- | index || Field || Global index of this room. |- | isAncientShelter || Field || Whether the room is an alpha-style big shelter. |- | mapPos || Field || Coordinate of the current room on automap. Affects BackgroundScenes. |- | name || Field || Name of the current room. Exactly matches that set in world_xx file (not the filename!) (case-sensitive!) |- | nodes || Field || Array of abstract world navigation nodes. When the room is abstracted, each entity occupies exactly one abstract room node{{Cn}}. |- | offScreenDen || Field || Whether this room is an offscreen den. |- | quantifiedCreatures || Field || {{Cn|what the hell is this 2d array}} |- | realizedRoom || Field || Realized layer of this room. Null when this room is not realized. |- | roomTags || Field || List of tags defined for this room in world_xx file, even if they are not recognized by the game. |- | size || Field || Tile dimensions of this room. |- | subregionName || Field || Name of the subregion this room belongs too. Null if none. |- | world || Field || [[../World|World]] this room belongs to. |- | gate || Property || Whether this room is a gate. |- | shelter || Property || Whether this room is a shelter. |- | scavengerOutpost || Property || Whether this room is a scav toll. |- | scavengerTrader || Property || Whether this room is a scav trade spot. |- | swarmRoom || Property || Whether this room is a swarmroom. |- | scavengerOutpost || Property || Whether this room is a scav toll. |- | scavengerOutpost || Property || Whether this room is a scav toll. |- | AddEntity || Method || Adds a new entity into the room. |- | RemoveEntity || Method || Removes an entity from the room (by ID or reference). |- | RealizeRoom || Method || Switches this room to Realized LOD. |- | Update || Method || Called by the containing World. '''Only called once every few frames; the "time" parameter tells it how many physics frames have passed since last update. This behavior is kept even when the room is realized.''' |} == Realized == {{todo}} 2e22563fd78d12cb653d76eae83d687946f7b960 532 531 2023-07-19T20:31:04Z Thalber 3 wikitext text/x-wiki '''Rooms''' are singular levels of the game, building blocks of a [[../World|world]]. Rooms exist in two [[../LOD|LOD]] levels: Abstract and Realized. == Abstract == Class for rooms in abstract LOD is AbstractRoom. Passes updates down to [[../AbstractWorldEntity|AbstractWorldEntities]]. === Lifecycle === Updates on this layer are only called once every few frames; the "time" parameter tells the room (and each entity) how many physics frames have passed since last update. This behavior is kept in abstract layer even when the room is realized. Abstract rooms are mostly instantiated on World.LoadWorld and related methods. Abstract rooms are destroyed when the World unloads. === Notable members === {| class="wikitable sortable" |+ |- ! Name !! Kind !! Description |- | connections || Field || Indices of rooms this room is connected to{{Cn}}. |- | dens || Field || Number of creature dens (unrelated to shelters) in room{{Cn}}. |- | creatures || Field || List of all creatures in current room. |- | entities || Field || List of all entities occupying current room's free space. Includes creatures. |- | entitiesInDens || Field || List of all entities occupying dens in current room. |- | exits || Field || Number of exits. |- | firstTimeRealized || Field || Whether next realization will be the first in current session. |- | gateIndex || Field || Index of the current room in this world's gate array, -1 if not a gate. |- | shelterIndex || Field || Index of the current room in this world's shelter array, -1 if not a shelter. |- | swarmRoomIndex || Property || Index of the current room in this world's swarmRoom array, -1 if not a swarmroom. |- | index || Field || Global index of this room. |- | isAncientShelter || Field || Whether the room is an alpha-style big shelter. |- | mapPos || Field || Coordinate of the current room on automap. Affects BackgroundScenes. |- | name || Field || Name of the current room. Exactly matches that set in world_xx file (not the filename!) (case-sensitive!) |- | nodes || Field || Array of abstract world navigation nodes. When the room is abstracted, each entity occupies exactly one abstract room node{{Cn}}. |- | offScreenDen || Field || Whether this room is an offscreen den. |- | quantifiedCreatures || Field || {{Cn|what the hell is this 2d array}} |- | realizedRoom || Field || Realized layer of this room. Null when this room is not realized. |- | roomTags || Field || List of tags defined for this room in world_xx file, even if they are not recognized by the game. |- | size || Field || Tile dimensions of this room. |- | subregionName || Field || Name of the subregion this room belongs too. Null if none. |- | world || Field || [[../World|World]] this room belongs to. |- | gate || Property || Whether this room is a gate. |- | shelter || Property || Whether this room is a shelter. |- | scavengerOutpost || Property || Whether this room is a scav toll. |- | scavengerTrader || Property || Whether this room is a scav trade spot. |- | swarmRoom || Property || Whether this room is a swarmroom. |- | scavengerOutpost || Property || Whether this room is a scav toll. |- | scavengerOutpost || Property || Whether this room is a scav toll. |- | AddEntity || Method || Adds a new entity into the room. |- | RemoveEntity || Method || Removes an entity from the room (by ID or reference). |- | RealizeRoom || Method || Switches this room to Realized LOD. |- | Update || Method || Called by the containing World. |} == Realized == Rooms in Realized LOD are '''Room'''. === Lifecycle === Rooms are updated every physics frame (40 TPS) by RainWorldGame directly. Rooms are constructed via RoomPreparer whenever an AbstractRoom is ordered to Realize. '''After construction, they go through gradual loading process before being available to creatures and the player'''. An important step in that initialization is Room.Loaded - it is called after the room is done loading basic data (geometry, AImaps) and performs things like spawning in consumable objects from devtools placed objects and effects. Rooms are destroyed when the owning AbstractRoom is ordered to abstractize, or when the World is unloaded. When a Room is unloaded on abstraction, all non-persistent entities (simple UpdatableAndDeletable children that are not PhysicalObject) are discarded as well. === Notable members === {| class="wikitable sortable" |+ |- ! Name !! Kind !! Description |- | aimap || Field || Object holding preprocessed AI navigation grids. |- | cameraPositions || Field || An array containing pixel offsets of all of the room's cameras. |- | game || Field || RainWorldGame this room belongs to. |- | world || Field || World this room belongs to. |- | abstractRoom || Property || Abstract counterpart this room belongs to. |- | gravity || Field || Global gravity multiplier for this room, works together (multiplicative) with every PhysicalObject's personal gravity. |- | lightSources || Field || List of all functional light sources in room (with all relevant gameplay effects, such as scaring away spiders). |- | cosmeticLightSources || Field || List of all light sources that do not affect gameplay. |- | physicalObjects || Field || List of everything in updateList that is a PhysicalObject. |- | drawableObjects || Property || List of all objects with graphics (implementing [[../IDrawable|IDrawable]]) in this room. |- | updateList || Property || List of all realized-level entities in this room, persisten or not. Some items are also in other members (see: Room.lightSources). |- | regionGate || Field || Region gate doors. Only exists in gates. |- | shelterDoor || Field || Shelter doors. Only exists in shelters. |- | shortcuts || Field || Array of structs representing data about all in-room shortcuts (triangle pipes). |- | Tiles || Field || 2D array of all tiles of the room. Getting tiles is best done via dedicated methods (GetTile) rather than indexing this array directly. |- | waterObject || Field || Object that represents the room's water (it is not an UpdatableAndDeletable! One per room!). |- | roomSettings || Field || Object that holds information about devtools settings of the room (placed objects, sounds, effects, etc). |- | roomRain || Field || Object that manages lethal end of cycle rain, flooding and other Game Over conditions. |- | BeingViewed || Property || Whether any camera is currently pointing at this room. |- | AddObject || Method || Adds an UpdatableAndDeletable to this room (updateList and any secondary lists if needed, such as drawableObjects). |- | DestroyObject || Method || Destroys an AbstractPhysicalObject with given ID. |- | RemoveObject || Method || Removes any UpdatableAndDeletable from the room. |- | GetTile || Method || Overloads of this method safely return a tile at a given position. Vector2 overload picks from under pixel coordinate, (int, int), WorldCoordinate and InteVector2 pick tile coordinate. These methods ''clamp tile position to room bounds'', which is why the geometry is extrapolated off room borders into infinity (a floor that goes past the end of the room in editor will be infinite ingame). |- | GetTilePosition || Method || Picks a tile that contains a given pixel coordinate and returns its coordinate as InteVector2. |- | GetWorldCoordinate || Method || Takes a tile position and contains it into a WorldCoordinate pointing to this room. |- | InGameNoise || Method || Causes a noise that alerts creatures. |- | Loaded || Method || Called by the game! Does a lot of stuff, mostly related to devtools settings. NOTE: game field may be null when this is being called. |- | NowViewed || Method || Called when the room becomes viewed by a camera. |- | NoLongerViewed || Method || Called when the room becomes no longer viewed by a camera. |- | Update || Method || Called every physics frame (40 TPS). Parameter "eu" stands for "even update", and is true every second frame. |- | PausedUpdate || Method || Called every render frame{{Cn}} only when the session is paused. |- | PlaySound || Method || Plays a non-looping sound by ID. |- | PlayDisembodiedLoop || Method || Plays a looping sound, which sounds the same regardless of where you are in the room, by ID. Remember to hold onto returned DisembodiedLoopEmitter! |- | PlayRectSound || Method || Plays a looping or non-looping sound in a rectangular area, fading out as you go away from it{{Cn}}. |- | PlayCustom... || Methods || All play a sound that does not have an ID, by name. These are loaded from <code>loadedsoundeffects</code> folder. Each call of these methods does file IO and is therefore considered slow! |- | PointSubmerged || Method || Checks whether a point is within the body of water. |- | SetAbstractRoom || Method || Reassigns this room to a different abstractRoom. Used when switching regions in gates. |- | Update || Method || Called by RainWorldGame every physics frame (40 TPS) |- | VisualContact || Method || Overload check whether it is possible to see directly from one position to another. |} 6eca6a70005a57a1cddf4ab0519760e32cf0dea6 Rain World Code Structure/RainWorld 0 188 533 443 2023-07-20T09:47:06Z Thalber 3 wikitext text/x-wiki {{todo}} '''RainWorld''' is a singleton [https://docs.unity3d.com/ScriptReference/MonoBehaviour.html MonoBehavior] that contains all of Rain World's code inside it - menus, game loop, options, etc. == Notable members == {| class="wikitable sortable" |+ |- ! Name !! Kind !! Description |- | processManager || field || [[../ProcessManager_and_Subprocesses|ProcessManager]] object that contains information about current game loops (menu / game session / pause menu etc) |- | Shaders || field || Dictionary of shaders used by the game, keyed by name. Make sure to add to add your custom shaders here if you want to make them accessible by other mods. |- | options || field || [[Rain_World_Code_Structure/Options|Options]] object that contains current user settings, including input config. |- | setup || field || A struct containing special setup values that can change some rules of the game (such as cycle length override). |- | GAME_VERSION_STRING || constant || Current game version as a string. |- | PreModsDisabledEnabled || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files#Mod_Lifecycle_Functions]] |- | OnModsEnabled || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files#Mod_Lifecycle_Functions]] |- | OnModsDisabled || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files#Mod_Lifecycle_Functions]] |- | PostModsDisabledEnabled || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files#Mod_Lifecycle_Functions]] |- | PreModsInit || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files#Mod_Lifecycle_Functions]] |- | OnModsInit || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files#Mod_Lifecycle_Functions]] |- | PostModsInit || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files#Mod_Lifecycle_Functions]] |- | LoadResources || method || Called when assets (such as spritesheets) are bulk loaded from disk to memory. |- | UnloadResources || method || Called before LoadResources needs to be called again. |- | LoadSetupValues || method || Loads setup values from <code>setup.txt</code> if one exists. Don't look inside. |} 4e8bc19da8daaf55518d77d50f19a48c6935a9c0 534 533 2023-07-20T09:54:28Z Thalber 3 wikitext text/x-wiki {{todo}} '''RainWorld''' is a singleton [https://docs.unity3d.com/ScriptReference/MonoBehaviour.html MonoBehavior] that contains all of Rain World's code inside it - menus, game loop, options, etc. RainWorld object is instantiated from a Unity serialized scene and persists through the game process' entire lifetime. == Notable members == {| class="wikitable sortable" |+ |- ! Name !! Kind !! Description |- | processManager || field || [[../ProcessManager_and_Subprocesses|ProcessManager]] object that contains information about current game loops (menu / game session / pause menu etc) |- | Shaders || field || Dictionary of shaders used by the game, keyed by name. Make sure to add to add your custom shaders here if you want to make them accessible by other mods. |- | options || field || [[Rain_World_Code_Structure/Options|Options]] object that contains current user settings, including input config. |- | setup || field || A struct containing special setup values that can change some rules of the game (such as cycle length override). |- | GAME_VERSION_STRING || constant || Current game version as a string. |- | PreModsDisabledEnabled || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files#Mod_Lifecycle_Functions|Mod Lifecycle Functions]]. |- | OnModsEnabled || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files#Mod_Lifecycle_Functions|Mod Lifecycle Functions]]. |- | OnModsDisabled || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files#Mod_Lifecycle_Functions|Mod Lifecycle Functions]]. |- | PostModsDisabledEnabled || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files#Mod_Lifecycle_Functions|Mod Lifecycle Functions]]. |- | PreModsInit || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files#Mod_Lifecycle_Functions|Mod Lifecycle Functions]]. |- | OnModsInit || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files#Mod_Lifecycle_Functions|Mod Lifecycle Functions]]. |- | PostModsInit || method || Hookable lifecycle method. See [[Downpour_Reference/BepInEx_Files#Mod_Lifecycle_Functions|Mod Lifecycle Functions]]. |- | LoadResources || method || Called when assets (such as spritesheets) are bulk loaded from disk to memory. |- | UnloadResources || method || Called before LoadResources needs to be called again. |- | LoadSetupValues || method || Loads setup values from <code>setup.txt</code> if one exists. Don't look inside. |} 6bd67e465784c99831f5af1c07eae81f73c16bc6 Rain World Code Structure/Options 0 206 535 2023-07-20T12:26:52Z Thalber 3 init wikitext text/x-wiki {{todo|target=article}} '''Options''' is a class containing user settings, such as screen resolution and control mappings. == Lifecycle == Options a singleton permanently attached to [[../RainWorld|RainWorld instance]]. It is constructed once, and is not destroyed until the game exits. == Notable members == Members with self-explanatory names are omitted. {| class="wikitable sortable" |+ AbstractWorldEntity useful members |- ! Member !! Kind !! Description |- | controls || Field || Array of ControlSetup objects defining keybinds for all players (index of ControlSetup corresponds to index of the player). |- | enabledMods || Field || ID strings of all currently enabled Remix mods. |- | language || Field || Currently selected language. |- | modLoadOrder || Field || Dictionary containing mod loading priorities. |- | saveSlot || Field || Index of currently selected saveslot. |- | resolution || Field || Index of currently selected resolution in Options.screenResolutions. |- | screenResolutions || Field || Array of all possible screen resolutions. |- | unrecognizedSaveStrings || Field || List of additional options data which the game could not recognize when deserealizing. |- | unrecognizedNonSyncedSaveStrings || Field || List of additional options data which the game could not recognize when deserealizing. These ones are specifically stored in files excluded from save sync (such as Steam Cloud). |} 66844fe2396fcbee2bd0feb64851dcddcdfbadb5 File:properties.png 6 207 536 2023-07-20T16:04:56Z XanTheDragon 202 An image of Visual Studio's Properties object, containing AssemblyInfo.cs wikitext text/x-wiki == Summary == An image of Visual Studio's Properties object, containing AssemblyInfo.cs abad23bc7198756500b10db70121987e1216b855 BepInPlugins 0 95 537 496 2023-07-20T16:41:03Z XanTheDragon 202 /* Step 3 - Hooking */ Tweak code block in anticipation of Part 2 changes. wikitext text/x-wiki BepInPlugins are the predominant form for Rain World code mods. They are a form of game mod native to [[BepInEx]]. They are not compatible with [[Partiality]]. == Creating a BepInPlugin == === Prerequisites === * A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary) * Rain World with RW BepInEx set up - see [[BepInEx|here]]. * Some kind of .NET programming environment, probably Visual Studio if you're on Windows, or Visual Studio Code for Linux/Mac. The guide below will assume you're already comfortable with the first prerequisite and your editor and environment of choice. ** The .NET Development pack for Visual Studio (or similar for other environments - you need to be able to use .NET Framework 4.8) === Step 1 - The project === Create a new C# .NET Framework 4.8 Class Library project in your IDE. You will then need to [https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019 add some references]. It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/core/BepInEx.dll</code> * <code>BepInEx/plugins/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/utils/PUBLIC-Assembly-CSharp.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.CoreModule.dll</code> === Step 2 - The BepInPlugin class === In a your new C# file, make a public class that has the <code>BepInEx.BepInPlugin</code> attribute and inherits from <code>BepInEx.BaseUnityPlugin</code> . The <code>BaseUnityPlugin</code> class inherits from <code>MonoBehaviour</code>, so you can use standard Unity script methods such as <code>OnEnable</code> and <code>OnDisable</code> in this class. The GUID should be unique to this plugin: something like "scholar" could be popular, which may result in BepInEx not loading your mod. Usually, people opt for the <code>username.mode_name</code> format. Include an assembly-level <code>SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)</code> declaration alongside your plugin class. This prevents errors later down the line. <syntaxhighlight lang="csharp"> using BepInEx; using System.Security.Permissions; [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] namespace SomeMod {     [BepInPlugin("author.my_mod_id", "SomeModName", "0.1.0")] // (GUID, mod name, mod version)     public class MyModName : BaseUnityPlugin     {     } } </syntaxhighlight> === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example: <syntaxhighlight lang="csharp"> namespace SomeMod { [BepInPlugin(PLUGIN_GUID, PLUGIN_NAME, PLUGIN_VERSION)] public class MyMod : BaseUnityPlugin {     public const string PLUGIN_GUID = "your_name.your_mod_id";     public const string PLUGIN_NAME = "Your Mod's Name";     public const string PLUGIN_VERSION = "1.0.0";     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         // Whenever Player.Update gets called by the game, it takes a detour into your code here instead. // Do anything that you need to happen when the player updates in here.         orig(self, eu); // Then, use this to to tell the game that it needs to run the normal code (and other mods' hooks) now. // And optionally, you can have more code here too, after orig // In general, you will want to always try to call orig // If you skip calling orig, this prevents all other mods from running their own hooks // and it also stops the game from doing the vanilla behavior.     } } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote> Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and find the Dynamic Link Library (DLL) file that it has compiled to. You then need to: # Create a folder and JSON for your mod, as described by [[Downpour Reference/Mod Directories]], and # Copy your mod DLL to a <code>plugins</code> folder within your mod's folder, as described by [[Downpour Reference/BepInEx Files]]. # Run the game and enable your mod by clicking on its name in the mod list in the Remix menu. Click the Apply Mods button. #* At time of writing, Rain World Remix does not support hot reloading of code mods, so the game needs to be restarted to apply your mod. == Enums == Due to their abundance in Rain World's code and their general usefulness in state machines, it's very possible that at some point you'll want to add your own value to an enum. To do that, you can use [[Downpour Reference/ExtEnum]]. == Advanced Techniques == === IL Hooking === IL hooking can be used to modify the Intermediate Language (IL) instructions of the game at runtime. This allows advanced editing of individual instructions within the game code. Risk of Thunder's guide to IL hooking can be found [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ here]. === RuntimeDetour === RuntimeDetour can be used to hook methods not covered by HOOKS-Assembly-CSharp.dll, as well as property getters and setters. A brief guide can be found on the [[MonoMod RuntimeDetour]] page. MonoMod's RuntimeDetour guide can be found [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md here]. === Harmony Patching === Harmony patching is a form of runtime patching. The HarmonyX wiki can be found [https://github.com/BepInEx/HarmonyX/wiki here]. [[Category:Code Mods]] e1b97a462a2c5565ab62172fbc6741ca15fef660 538 537 2023-07-20T16:44:05Z XanTheDragon 202 /* Step 2 - The BepInPlugin class */ Append instructions on BepInDependency. wikitext text/x-wiki BepInPlugins are the predominant form for Rain World code mods. They are a form of game mod native to [[BepInEx]]. They are not compatible with [[Partiality]]. == Creating a BepInPlugin == === Prerequisites === * A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary) * Rain World with RW BepInEx set up - see [[BepInEx|here]]. * Some kind of .NET programming environment, probably Visual Studio if you're on Windows, or Visual Studio Code for Linux/Mac. The guide below will assume you're already comfortable with the first prerequisite and your editor and environment of choice. ** The .NET Development pack for Visual Studio (or similar for other environments - you need to be able to use .NET Framework 4.8) === Step 1 - The project === Create a new C# .NET Framework 4.8 Class Library project in your IDE. You will then need to [https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019 add some references]. It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/core/BepInEx.dll</code> * <code>BepInEx/plugins/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/utils/PUBLIC-Assembly-CSharp.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.CoreModule.dll</code> === Step 2 - The BepInPlugin class === This section requires care. ==== Step 2.1 - Setting up the Mod Main class ==== When you start up a project, it will have a default file in it named Class1.cs and it should be automatically open. You'll see some default code within it. Start by coming up with a class name. This is basically a way for you (and other code) to find your mod's main class. A generally acceptable naming convention is <code>ModNameMain</code>, for example, <code>SuperJumpBootsMain</code> is a sensible hypothetical name. If you are using Visual Studio, click on the class's name in code (Class1) and hold Left Ctrl, then press the R key twice. This will open the rename prompt, which will automatically edit every single piece of code that refers to that class, and it will also rename the file for you. Once this is done, your class needs to extend <code>BaseUnityPlugin</code>. You should also make a private method named <code>OnEnable</code>. Once that is done, it should look a bit like this: <syntaxhighlight lang="csharp"> namespace YourMod { public class ModNameMain : BaseUnityPlugin { private void OnEnable() { // Some modders also opt to use Awake() instead of OnEnable() - if you see that, it functions roughly the same. } } } </syntaxhighlight> If you are familiar with Unity development, <code>BepInPlugin</code> is a <code>MonoBehaviour</code> and all message methods are available to you. If you don't know what this means, that's okay. ==== Step 2.2 - Setting up the assembly ==== First, we need to declare a preliminary attribute on the assembly itself to prevent errors. To do this, view your Solution Explorer (it's on the right, where your files are listed in Visual Studio) and open the "Properties" object. Open AssemblyInfo.cs <br/> [[File:properties.png|frameless|The AssemblyInfo.cs file is located within the Properties object.]]<br/> ''An example from the Superstructure Fuse Fix mod.'' At the top of AssemblyInfo.cs, paste this line. You should see other lines starting with <code>using</code> to put it below. <syntaxhighlight lang="csharp"> using System.Security.Permissions; </syntaxhighlight> And then at the bottom of the file, paste this code: <syntaxhighlight lang="csharp"> #pragma warning disable CS0618 // SecurityAction.RequestMinimum is obsolete. However, this does not apply to the mod, which still needs it. Suppress the warning indicating that it is obsolete. [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] #pragma warning restore CS0618 </syntaxhighlight> Save AssemblyInfo.cs and close it, that is all that needs to be done with that file. Return to <code>ModNameMain.cs</code> (or Class1.cs, if you didn't rename it, which you should do now). ==== Step 2.3 - Setting up the mod's information ==== Now, you need to apply the appropriate attributes to your mod class. The most important of these is the <code>BepInPlugin</code> attribute, as it is responsible for storing your mod's unique ID, display name, and version. Please note that there are certain guidelines to follow when coming up with data for your mod: * Your plugin GUID ''must'' be unique, so that it does not clash with anyone else's mod. A great way to do this is following a format like <code>your_name.mod_id</code>. If it is not unique, it will break both your mod '''and''' the other person's mod, if they are both installed. * ''Match your plugin GUID with the mod ID you made for modinfo.json - they should be identical''. This ensures that other modders have an easily accessible way to find your mod's ID. * Once you decide on a GUID, ''do not change it after you release your mod''. This can wreak havoc on any mods that depend on yours! You '''can''' replace the display name at any time, just not the GUID. To declare these, start by making three <code>public const string</code> fields in your class. Use them in the <code>BepInPlugin</code> constructor. Some mods use dependencies, for example, SlugBase and RegionKit are two very popular choices. '''Not only do you need to add these dependencies to your modinfo.json, but you also need to add them to your mod's code!''' If you forget to do this, there is a chance your mod could load ''before'' a mod that you require, which means its code hasn't loaded yet. This will cause the game to crash on startup, or cause the mod to error out and do nothing. To register a dependency in your code, use the <code>BepInDependency</code> attribute, like so: <syntaxhighlight lang="csharp"> using BepInEx; namespace SomeMod { // In general, it is considered bad form to directly put strings into the constructor of the attribute. // By creating const string fields, other mods that depend on yours can import your mod's DLL file, and then their code can actually directly reference the data you put here! // This saves your fellow modders a lot of time and headache, and could potentially save you in the future too.     [BepInPlugin(PLUGIN_GUID, PLUGIN_NAME, PLUGIN_VERSION)] // There are two types of dependencies: // 1. BepInDependency.DependencyFlags.HardDependency - The other mod *MUST* be installed, and your mod cannot run without it. This ensures their mod loads before yours, preventing errors. // 2. BepInDependency.DependencyFlags.SoftDependency - The other mod doesn't need to be installed, but if it is, it should load before yours. [BepInDependency("author.some_other_mods_guid", BepInDependency.DependencyFlags.HardDependency)] // As mentioned before, if the other modder uses constant strings, you can do something like this instead: // [BepInDependency(SomeOtherModMain.PLUGIN_GUID, BepInDependency.DependencyFlags.HardDependency)]     public class MyModName : BaseUnityPlugin     {         public const string PLUGIN_GUID = "your_name.your_mod_id"; // This should be the same as the id in modinfo.json!         public const string PLUGIN_NAME = "Your Mod's Name"; // This should be a human-readable version of your mod's name. This is used for log files and also displaying which mods get loaded. In general, it's a good idea to match this with your modinfo.json as well.         public const string PLUGIN_VERSION = "1.0.0"; // This follows semantic versioning. For more information, see https://semver.org/ - again, match what you have in modinfo.json private void OnEnable() { }     } } </syntaxhighlight> Once this is done, your code is fully prepared to facilitate everything you need for your mod to work! === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example: <syntaxhighlight lang="csharp"> namespace SomeMod { [BepInPlugin(PLUGIN_GUID, PLUGIN_NAME, PLUGIN_VERSION)] public class MyMod : BaseUnityPlugin {     public const string PLUGIN_GUID = "your_name.your_mod_id";     public const string PLUGIN_NAME = "Your Mod's Name";     public const string PLUGIN_VERSION = "1.0.0";     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         // Whenever Player.Update gets called by the game, it takes a detour into your code here instead. // Do anything that you need to happen when the player updates in here.         orig(self, eu); // Then, use this to to tell the game that it needs to run the normal code (and other mods' hooks) now. // And optionally, you can have more code here too, after orig // In general, you will want to always try to call orig // If you skip calling orig, this prevents all other mods from running their own hooks // and it also stops the game from doing the vanilla behavior.     } } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote> Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and find the Dynamic Link Library (DLL) file that it has compiled to. You then need to: # Create a folder and JSON for your mod, as described by [[Downpour Reference/Mod Directories]], and # Copy your mod DLL to a <code>plugins</code> folder within your mod's folder, as described by [[Downpour Reference/BepInEx Files]]. # Run the game and enable your mod by clicking on its name in the mod list in the Remix menu. Click the Apply Mods button. #* At time of writing, Rain World Remix does not support hot reloading of code mods, so the game needs to be restarted to apply your mod. == Enums == Due to their abundance in Rain World's code and their general usefulness in state machines, it's very possible that at some point you'll want to add your own value to an enum. To do that, you can use [[Downpour Reference/ExtEnum]]. == Advanced Techniques == === IL Hooking === IL hooking can be used to modify the Intermediate Language (IL) instructions of the game at runtime. This allows advanced editing of individual instructions within the game code. Risk of Thunder's guide to IL hooking can be found [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ here]. === RuntimeDetour === RuntimeDetour can be used to hook methods not covered by HOOKS-Assembly-CSharp.dll, as well as property getters and setters. A brief guide can be found on the [[MonoMod RuntimeDetour]] page. MonoMod's RuntimeDetour guide can be found [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md here]. === Harmony Patching === Harmony patching is a form of runtime patching. The HarmonyX wiki can be found [https://github.com/BepInEx/HarmonyX/wiki here]. [[Category:Code Mods]] 8b84d56275322bd95d2a9876828ce9b6bdc8ed98 539 538 2023-07-20T16:49:10Z XanTheDragon 202 /* Step 2.3 - Setting up the mod's information */ Improve grammar and code presentation wikitext text/x-wiki BepInPlugins are the predominant form for Rain World code mods. They are a form of game mod native to [[BepInEx]]. They are not compatible with [[Partiality]]. == Creating a BepInPlugin == === Prerequisites === * A solid understanding of some key concepts including C# syntax and environment, and Unity (good but not necessary) * Rain World with RW BepInEx set up - see [[BepInEx|here]]. * Some kind of .NET programming environment, probably Visual Studio if you're on Windows, or Visual Studio Code for Linux/Mac. The guide below will assume you're already comfortable with the first prerequisite and your editor and environment of choice. ** The .NET Development pack for Visual Studio (or similar for other environments - you need to be able to use .NET Framework 4.8) === Step 1 - The project === Create a new C# .NET Framework 4.8 Class Library project in your IDE. You will then need to [https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019 add some references]. It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/core/BepInEx.dll</code> * <code>BepInEx/plugins/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/utils/PUBLIC-Assembly-CSharp.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.CoreModule.dll</code> === Step 2 - The BepInPlugin class === This section requires care. ==== Step 2.1 - Setting up the Mod Main class ==== When you start up a project, it will have a default file in it named Class1.cs and it should be automatically open. You'll see some default code within it. Start by coming up with a class name. This is basically a way for you (and other code) to find your mod's main class. A generally acceptable naming convention is <code>ModNameMain</code>, for example, <code>SuperJumpBootsMain</code> is a sensible hypothetical name. If you are using Visual Studio, click on the class's name in code (Class1) and hold Left Ctrl, then press the R key twice. This will open the rename prompt, which will automatically edit every single piece of code that refers to that class, and it will also rename the file for you. Once this is done, your class needs to extend <code>BaseUnityPlugin</code>. You should also make a private method named <code>OnEnable</code>. Once that is done, it should look a bit like this: <syntaxhighlight lang="csharp"> namespace YourMod { public class ModNameMain : BaseUnityPlugin { private void OnEnable() { // Some modders also opt to use Awake() instead of OnEnable() - if you see that, it functions roughly the same. } } } </syntaxhighlight> If you are familiar with Unity development, <code>BepInPlugin</code> is a <code>MonoBehaviour</code> and all message methods are available to you. If you don't know what this means, that's okay. ==== Step 2.2 - Setting up the assembly ==== First, we need to declare a preliminary attribute on the assembly itself to prevent errors. To do this, view your Solution Explorer (it's on the right, where your files are listed in Visual Studio) and open the "Properties" object. Open AssemblyInfo.cs <br/> [[File:properties.png|frameless|The AssemblyInfo.cs file is located within the Properties object.]]<br/> ''An example from the Superstructure Fuse Fix mod.'' At the top of AssemblyInfo.cs, paste this line. You should see other lines starting with <code>using</code> to put it below. <syntaxhighlight lang="csharp"> using System.Security.Permissions; </syntaxhighlight> And then at the bottom of the file, paste this code: <syntaxhighlight lang="csharp"> #pragma warning disable CS0618 // SecurityAction.RequestMinimum is obsolete. However, this does not apply to the mod, which still needs it. Suppress the warning indicating that it is obsolete. [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] #pragma warning restore CS0618 </syntaxhighlight> Save AssemblyInfo.cs and close it, that is all that needs to be done with that file. Return to <code>ModNameMain.cs</code> (or Class1.cs, if you didn't rename it, which you should do now). ==== Step 2.3 - Setting up the mod's information ==== Now, you need to apply the appropriate attributes to your mod class. The most important of these is the <code>BepInPlugin</code> attribute, as it is responsible for storing your mod's unique ID, display name, and version. Please note that there are certain guidelines to follow when coming up with data for your mod: * Your plugin GUID ''must'' be unique, so that it does not clash with anyone else's mod. A great way to do this is following a format like <code>your_name.mod_id</code>. If it is not unique, it will break both your mod '''and''' the other person's mod, if they are both installed. * ''Match your plugin GUID with the mod ID you made for modinfo.json - they should be identical''. This ensures that other modders have an easily accessible way to find your mod's ID. * Once you decide on a GUID, ''do not change it after you release your mod''. This can wreak havoc on any mods that depend on yours! You '''can''' replace the display name at any time, just not the GUID. To declare these, start by making three <code>public const string</code> fields in your class. Use them in the <code>BepInPlugin</code> constructor. Some mods use dependencies, for example, SlugBase and RegionKit are two very popular choices. '''Not only do you need to add these dependencies to your modinfo.json, but you also need to add them to your mod's code!''' If you forget to do this, there is a chance your mod could load ''before'' a mod that you require, which means its code hasn't loaded yet. This will cause the game to crash on startup, or cause the mod to error out and do nothing. To register a dependency in your code, use the <code>BepInDependency</code> attribute. When you put this all together, it should look like this: <syntaxhighlight lang="csharp"> using BepInEx; namespace SomeMod { // There are two types of dependencies: // 1. BepInDependency.DependencyFlags.HardDependency - The other mod *MUST* be installed, and your mod cannot run without it. This ensures their mod loads before yours, preventing errors. // 2. BepInDependency.DependencyFlags.SoftDependency - The other mod doesn't need to be installed, but if it is, it should load before yours. [BepInDependency("author.some_other_mods_guid", BepInDependency.DependencyFlags.HardDependency)] // Of course, you should erase the line above. It's just an example. // As mentioned before, if the other modder uses constant strings, you can do something like this instead: // [BepInDependency(SomeOtherModMain.PLUGIN_GUID, BepInDependency.DependencyFlags.HardDependency)] // In general, it is considered bad form to directly put strings into the constructor of the BepInPlugin attribute. // By creating const string fields, other mods that depend on yours can import your mod's DLL file, and then their code can actually directly reference the data you put here! // This saves your fellow modders a lot of time and headache, and could potentially save you in the future too.     [BepInPlugin(PLUGIN_GUID, PLUGIN_NAME, PLUGIN_VERSION)]     public class MyModName : BaseUnityPlugin     {         public const string PLUGIN_GUID = "your_name.your_mod_id"; // This should be the same as the id in modinfo.json!         public const string PLUGIN_NAME = "Your Mod's Name"; // This should be a human-readable version of your mod's name. This is used for log files and also displaying which mods get loaded. In general, it's a good idea to match this with your modinfo.json as well.         public const string PLUGIN_VERSION = "1.0.0"; // This follows semantic versioning. For more information, see https://semver.org/ - again, match what you have in modinfo.json // It should go without saying, but for this to benefit other modders, the class *and* these const strings must be public. private void OnEnable() { }     } } </syntaxhighlight> Once this is done, your code is fully prepared to facilitate everything you need for your mod to work! === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example: <syntaxhighlight lang="csharp"> namespace SomeMod { [BepInPlugin(PLUGIN_GUID, PLUGIN_NAME, PLUGIN_VERSION)] public class MyMod : BaseUnityPlugin {     public const string PLUGIN_GUID = "your_name.your_mod_id";     public const string PLUGIN_NAME = "Your Mod's Name";     public const string PLUGIN_VERSION = "1.0.0";     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         // Whenever Player.Update gets called by the game, it takes a detour into your code here instead. // Do anything that you need to happen when the player updates in here.         orig(self, eu); // Then, use this to to tell the game that it needs to run the normal code (and other mods' hooks) now. // And optionally, you can have more code here too, after orig // In general, you will want to always try to call orig // If you skip calling orig, this prevents all other mods from running their own hooks // and it also stops the game from doing the vanilla behavior.     } } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote> Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and find the Dynamic Link Library (DLL) file that it has compiled to. You then need to: # Create a folder and JSON for your mod, as described by [[Downpour Reference/Mod Directories]], and # Copy your mod DLL to a <code>plugins</code> folder within your mod's folder, as described by [[Downpour Reference/BepInEx Files]]. # Run the game and enable your mod by clicking on its name in the mod list in the Remix menu. Click the Apply Mods button. #* At time of writing, Rain World Remix does not support hot reloading of code mods, so the game needs to be restarted to apply your mod. == Enums == Due to their abundance in Rain World's code and their general usefulness in state machines, it's very possible that at some point you'll want to add your own value to an enum. To do that, you can use [[Downpour Reference/ExtEnum]]. == Advanced Techniques == === IL Hooking === IL hooking can be used to modify the Intermediate Language (IL) instructions of the game at runtime. This allows advanced editing of individual instructions within the game code. Risk of Thunder's guide to IL hooking can be found [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ here]. === RuntimeDetour === RuntimeDetour can be used to hook methods not covered by HOOKS-Assembly-CSharp.dll, as well as property getters and setters. A brief guide can be found on the [[MonoMod RuntimeDetour]] page. MonoMod's RuntimeDetour guide can be found [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md here]. === Harmony Patching === Harmony patching is a form of runtime patching. The HarmonyX wiki can be found [https://github.com/BepInEx/HarmonyX/wiki here]. [[Category:Code Mods]] 7a325bbbf40e1bacfae18f4133d87741218dbc80 541 539 2023-07-30T04:36:52Z XanTheDragon 202 /* Prerequisites */ Provide a link to Microsoft's dev tools landing page, and a link to .NET Framework 4.8. Remove the link to the legacy 1.5 modding page as it is not generally applicable to modern modders. wikitext text/x-wiki BepInPlugins are the predominant form for Rain World code mods. They are a form of game mod native to [[BepInEx]]. They are not compatible with [[Partiality]]. == Creating a BepInPlugin == === Prerequisites === Before you will be able to make a mod, you need the following: * Beginner knowledge of C#, such that you are comfortable with your current level of skill. ** If you understand the concept of object oriented programming as well as main C# elements such as methods, fields, properties, events, and delegates, you should be set to go. ** Unity knowledge is optional, but useful for advanced modding. Unlike other BepInEx-modded games, Rain World's ties into Unity are sparse due to the use of the Futile engine wrapper, thus the knowledge is not required. * Entry-level skills in reverse engineering, using tools like [https://github.com/dnSpy/dnSpy dnSpy] (or any other .NET decompiler of your choosing). * A .NET programming environment. You can view feasible options here: https://dotnet.microsoft.com/en-us/platform/tools ** Windows users will want Visual Studio (''not'' Visual Studio Code, they are similar but not the same!) * .NET Framework 4.8 '''Developer Pack''' (not runtime!) which you can download here: https://dotnet.microsoft.com/en-us/download/dotnet-framework/net48 === Step 1 - The project === Create a new C# .NET Framework 4.8 Class Library project in your IDE. You will then need to [https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019 add some references]. It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/core/BepInEx.dll</code> * <code>BepInEx/plugins/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/utils/PUBLIC-Assembly-CSharp.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.CoreModule.dll</code> === Step 2 - The BepInPlugin class === This section requires care. ==== Step 2.1 - Setting up the Mod Main class ==== When you start up a project, it will have a default file in it named Class1.cs and it should be automatically open. You'll see some default code within it. Start by coming up with a class name. This is basically a way for you (and other code) to find your mod's main class. A generally acceptable naming convention is <code>ModNameMain</code>, for example, <code>SuperJumpBootsMain</code> is a sensible hypothetical name. If you are using Visual Studio, click on the class's name in code (Class1) and hold Left Ctrl, then press the R key twice. This will open the rename prompt, which will automatically edit every single piece of code that refers to that class, and it will also rename the file for you. Once this is done, your class needs to extend <code>BaseUnityPlugin</code>. You should also make a private method named <code>OnEnable</code>. Once that is done, it should look a bit like this: <syntaxhighlight lang="csharp"> namespace YourMod { public class ModNameMain : BaseUnityPlugin { private void OnEnable() { // Some modders also opt to use Awake() instead of OnEnable() - if you see that, it functions roughly the same. } } } </syntaxhighlight> If you are familiar with Unity development, <code>BepInPlugin</code> is a <code>MonoBehaviour</code> and all message methods are available to you. If you don't know what this means, that's okay. ==== Step 2.2 - Setting up the assembly ==== First, we need to declare a preliminary attribute on the assembly itself to prevent errors. To do this, view your Solution Explorer (it's on the right, where your files are listed in Visual Studio) and open the "Properties" object. Open AssemblyInfo.cs <br/> [[File:properties.png|frameless|The AssemblyInfo.cs file is located within the Properties object.]]<br/> ''An example from the Superstructure Fuse Fix mod.'' At the top of AssemblyInfo.cs, paste this line. You should see other lines starting with <code>using</code> to put it below. <syntaxhighlight lang="csharp"> using System.Security.Permissions; </syntaxhighlight> And then at the bottom of the file, paste this code: <syntaxhighlight lang="csharp"> #pragma warning disable CS0618 // SecurityAction.RequestMinimum is obsolete. However, this does not apply to the mod, which still needs it. Suppress the warning indicating that it is obsolete. [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] #pragma warning restore CS0618 </syntaxhighlight> Save AssemblyInfo.cs and close it, that is all that needs to be done with that file. Return to <code>ModNameMain.cs</code> (or Class1.cs, if you didn't rename it, which you should do now). ==== Step 2.3 - Setting up the mod's information ==== Now, you need to apply the appropriate attributes to your mod class. The most important of these is the <code>BepInPlugin</code> attribute, as it is responsible for storing your mod's unique ID, display name, and version. Please note that there are certain guidelines to follow when coming up with data for your mod: * Your plugin GUID ''must'' be unique, so that it does not clash with anyone else's mod. A great way to do this is following a format like <code>your_name.mod_id</code>. If it is not unique, it will break both your mod '''and''' the other person's mod, if they are both installed. * ''Match your plugin GUID with the mod ID you made for modinfo.json - they should be identical''. This ensures that other modders have an easily accessible way to find your mod's ID. * Once you decide on a GUID, ''do not change it after you release your mod''. This can wreak havoc on any mods that depend on yours! You '''can''' replace the display name at any time, just not the GUID. To declare these, start by making three <code>public const string</code> fields in your class. Use them in the <code>BepInPlugin</code> constructor. Some mods use dependencies, for example, SlugBase and RegionKit are two very popular choices. '''Not only do you need to add these dependencies to your modinfo.json, but you also need to add them to your mod's code!''' If you forget to do this, there is a chance your mod could load ''before'' a mod that you require, which means its code hasn't loaded yet. This will cause the game to crash on startup, or cause the mod to error out and do nothing. To register a dependency in your code, use the <code>BepInDependency</code> attribute. When you put this all together, it should look like this: <syntaxhighlight lang="csharp"> using BepInEx; namespace SomeMod { // There are two types of dependencies: // 1. BepInDependency.DependencyFlags.HardDependency - The other mod *MUST* be installed, and your mod cannot run without it. This ensures their mod loads before yours, preventing errors. // 2. BepInDependency.DependencyFlags.SoftDependency - The other mod doesn't need to be installed, but if it is, it should load before yours. [BepInDependency("author.some_other_mods_guid", BepInDependency.DependencyFlags.HardDependency)] // Of course, you should erase the line above. It's just an example. // As mentioned before, if the other modder uses constant strings, you can do something like this instead: // [BepInDependency(SomeOtherModMain.PLUGIN_GUID, BepInDependency.DependencyFlags.HardDependency)] // In general, it is considered bad form to directly put strings into the constructor of the BepInPlugin attribute. // By creating const string fields, other mods that depend on yours can import your mod's DLL file, and then their code can actually directly reference the data you put here! // This saves your fellow modders a lot of time and headache, and could potentially save you in the future too.     [BepInPlugin(PLUGIN_GUID, PLUGIN_NAME, PLUGIN_VERSION)]     public class MyModName : BaseUnityPlugin     {         public const string PLUGIN_GUID = "your_name.your_mod_id"; // This should be the same as the id in modinfo.json!         public const string PLUGIN_NAME = "Your Mod's Name"; // This should be a human-readable version of your mod's name. This is used for log files and also displaying which mods get loaded. In general, it's a good idea to match this with your modinfo.json as well.         public const string PLUGIN_VERSION = "1.0.0"; // This follows semantic versioning. For more information, see https://semver.org/ - again, match what you have in modinfo.json // It should go without saying, but for this to benefit other modders, the class *and* these const strings must be public. private void OnEnable() { }     } } </syntaxhighlight> Once this is done, your code is fully prepared to facilitate everything you need for your mod to work! === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example: <syntaxhighlight lang="csharp"> namespace SomeMod { [BepInPlugin(PLUGIN_GUID, PLUGIN_NAME, PLUGIN_VERSION)] public class MyMod : BaseUnityPlugin {     public const string PLUGIN_GUID = "your_name.your_mod_id";     public const string PLUGIN_NAME = "Your Mod's Name";     public const string PLUGIN_VERSION = "1.0.0";     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         // Whenever Player.Update gets called by the game, it takes a detour into your code here instead. // Do anything that you need to happen when the player updates in here.         orig(self, eu); // Then, use this to to tell the game that it needs to run the normal code (and other mods' hooks) now. // And optionally, you can have more code here too, after orig // In general, you will want to always try to call orig // If you skip calling orig, this prevents all other mods from running their own hooks // and it also stops the game from doing the vanilla behavior.     } } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote> Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and find the Dynamic Link Library (DLL) file that it has compiled to. You then need to: # Create a folder and JSON for your mod, as described by [[Downpour Reference/Mod Directories]], and # Copy your mod DLL to a <code>plugins</code> folder within your mod's folder, as described by [[Downpour Reference/BepInEx Files]]. # Run the game and enable your mod by clicking on its name in the mod list in the Remix menu. Click the Apply Mods button. #* At time of writing, Rain World Remix does not support hot reloading of code mods, so the game needs to be restarted to apply your mod. == Enums == Due to their abundance in Rain World's code and their general usefulness in state machines, it's very possible that at some point you'll want to add your own value to an enum. To do that, you can use [[Downpour Reference/ExtEnum]]. == Advanced Techniques == === IL Hooking === IL hooking can be used to modify the Intermediate Language (IL) instructions of the game at runtime. This allows advanced editing of individual instructions within the game code. Risk of Thunder's guide to IL hooking can be found [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ here]. === RuntimeDetour === RuntimeDetour can be used to hook methods not covered by HOOKS-Assembly-CSharp.dll, as well as property getters and setters. A brief guide can be found on the [[MonoMod RuntimeDetour]] page. MonoMod's RuntimeDetour guide can be found [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md here]. === Harmony Patching === Harmony patching is a form of runtime patching. The HarmonyX wiki can be found [https://github.com/BepInEx/HarmonyX/wiki here]. [[Category:Code Mods]] 6003c0472bd87426b0c9ff9553ae8ce5603824e5 542 541 2023-07-30T04:38:27Z XanTheDragon 202 /* Step 1 - The project */ Add mention of potentially needing more DLL files. wikitext text/x-wiki BepInPlugins are the predominant form for Rain World code mods. They are a form of game mod native to [[BepInEx]]. They are not compatible with [[Partiality]]. == Creating a BepInPlugin == === Prerequisites === Before you will be able to make a mod, you need the following: * Beginner knowledge of C#, such that you are comfortable with your current level of skill. ** If you understand the concept of object oriented programming as well as main C# elements such as methods, fields, properties, events, and delegates, you should be set to go. ** Unity knowledge is optional, but useful for advanced modding. Unlike other BepInEx-modded games, Rain World's ties into Unity are sparse due to the use of the Futile engine wrapper, thus the knowledge is not required. * Entry-level skills in reverse engineering, using tools like [https://github.com/dnSpy/dnSpy dnSpy] (or any other .NET decompiler of your choosing). * A .NET programming environment. You can view feasible options here: https://dotnet.microsoft.com/en-us/platform/tools ** Windows users will want Visual Studio (''not'' Visual Studio Code, they are similar but not the same!) * .NET Framework 4.8 '''Developer Pack''' (not runtime!) which you can download here: https://dotnet.microsoft.com/en-us/download/dotnet-framework/net48 === Step 1 - The project === Create a new C# .NET Framework 4.8 Class Library project in your IDE. You will then need to [https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019 add some references]. It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/core/BepInEx.dll</code> * <code>BepInEx/plugins/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/utils/PUBLIC-Assembly-CSharp.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.CoreModule.dll</code> Note that certain mods may need more functionality from Unity. In the <code>RainWorld_Data/Managed</code> folder you will find DLL files prefixed with <code>UnityEngine.</code> - these are different parts of the Unity engine that allow doing different things, such as <code>UnityEngine.AssetBundleModule</code> for loading asset bundles built in the Unity editor. === Step 2 - The BepInPlugin class === This section requires care. ==== Step 2.1 - Setting up the Mod Main class ==== When you start up a project, it will have a default file in it named Class1.cs and it should be automatically open. You'll see some default code within it. Start by coming up with a class name. This is basically a way for you (and other code) to find your mod's main class. A generally acceptable naming convention is <code>ModNameMain</code>, for example, <code>SuperJumpBootsMain</code> is a sensible hypothetical name. If you are using Visual Studio, click on the class's name in code (Class1) and hold Left Ctrl, then press the R key twice. This will open the rename prompt, which will automatically edit every single piece of code that refers to that class, and it will also rename the file for you. Once this is done, your class needs to extend <code>BaseUnityPlugin</code>. You should also make a private method named <code>OnEnable</code>. Once that is done, it should look a bit like this: <syntaxhighlight lang="csharp"> namespace YourMod { public class ModNameMain : BaseUnityPlugin { private void OnEnable() { // Some modders also opt to use Awake() instead of OnEnable() - if you see that, it functions roughly the same. } } } </syntaxhighlight> If you are familiar with Unity development, <code>BepInPlugin</code> is a <code>MonoBehaviour</code> and all message methods are available to you. If you don't know what this means, that's okay. ==== Step 2.2 - Setting up the assembly ==== First, we need to declare a preliminary attribute on the assembly itself to prevent errors. To do this, view your Solution Explorer (it's on the right, where your files are listed in Visual Studio) and open the "Properties" object. Open AssemblyInfo.cs <br/> [[File:properties.png|frameless|The AssemblyInfo.cs file is located within the Properties object.]]<br/> ''An example from the Superstructure Fuse Fix mod.'' At the top of AssemblyInfo.cs, paste this line. You should see other lines starting with <code>using</code> to put it below. <syntaxhighlight lang="csharp"> using System.Security.Permissions; </syntaxhighlight> And then at the bottom of the file, paste this code: <syntaxhighlight lang="csharp"> #pragma warning disable CS0618 // SecurityAction.RequestMinimum is obsolete. However, this does not apply to the mod, which still needs it. Suppress the warning indicating that it is obsolete. [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] #pragma warning restore CS0618 </syntaxhighlight> Save AssemblyInfo.cs and close it, that is all that needs to be done with that file. Return to <code>ModNameMain.cs</code> (or Class1.cs, if you didn't rename it, which you should do now). ==== Step 2.3 - Setting up the mod's information ==== Now, you need to apply the appropriate attributes to your mod class. The most important of these is the <code>BepInPlugin</code> attribute, as it is responsible for storing your mod's unique ID, display name, and version. Please note that there are certain guidelines to follow when coming up with data for your mod: * Your plugin GUID ''must'' be unique, so that it does not clash with anyone else's mod. A great way to do this is following a format like <code>your_name.mod_id</code>. If it is not unique, it will break both your mod '''and''' the other person's mod, if they are both installed. * ''Match your plugin GUID with the mod ID you made for modinfo.json - they should be identical''. This ensures that other modders have an easily accessible way to find your mod's ID. * Once you decide on a GUID, ''do not change it after you release your mod''. This can wreak havoc on any mods that depend on yours! You '''can''' replace the display name at any time, just not the GUID. To declare these, start by making three <code>public const string</code> fields in your class. Use them in the <code>BepInPlugin</code> constructor. Some mods use dependencies, for example, SlugBase and RegionKit are two very popular choices. '''Not only do you need to add these dependencies to your modinfo.json, but you also need to add them to your mod's code!''' If you forget to do this, there is a chance your mod could load ''before'' a mod that you require, which means its code hasn't loaded yet. This will cause the game to crash on startup, or cause the mod to error out and do nothing. To register a dependency in your code, use the <code>BepInDependency</code> attribute. When you put this all together, it should look like this: <syntaxhighlight lang="csharp"> using BepInEx; namespace SomeMod { // There are two types of dependencies: // 1. BepInDependency.DependencyFlags.HardDependency - The other mod *MUST* be installed, and your mod cannot run without it. This ensures their mod loads before yours, preventing errors. // 2. BepInDependency.DependencyFlags.SoftDependency - The other mod doesn't need to be installed, but if it is, it should load before yours. [BepInDependency("author.some_other_mods_guid", BepInDependency.DependencyFlags.HardDependency)] // Of course, you should erase the line above. It's just an example. // As mentioned before, if the other modder uses constant strings, you can do something like this instead: // [BepInDependency(SomeOtherModMain.PLUGIN_GUID, BepInDependency.DependencyFlags.HardDependency)] // In general, it is considered bad form to directly put strings into the constructor of the BepInPlugin attribute. // By creating const string fields, other mods that depend on yours can import your mod's DLL file, and then their code can actually directly reference the data you put here! // This saves your fellow modders a lot of time and headache, and could potentially save you in the future too.     [BepInPlugin(PLUGIN_GUID, PLUGIN_NAME, PLUGIN_VERSION)]     public class MyModName : BaseUnityPlugin     {         public const string PLUGIN_GUID = "your_name.your_mod_id"; // This should be the same as the id in modinfo.json!         public const string PLUGIN_NAME = "Your Mod's Name"; // This should be a human-readable version of your mod's name. This is used for log files and also displaying which mods get loaded. In general, it's a good idea to match this with your modinfo.json as well.         public const string PLUGIN_VERSION = "1.0.0"; // This follows semantic versioning. For more information, see https://semver.org/ - again, match what you have in modinfo.json // It should go without saying, but for this to benefit other modders, the class *and* these const strings must be public. private void OnEnable() { }     } } </syntaxhighlight> Once this is done, your code is fully prepared to facilitate everything you need for your mod to work! === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example: <syntaxhighlight lang="csharp"> namespace SomeMod { [BepInPlugin(PLUGIN_GUID, PLUGIN_NAME, PLUGIN_VERSION)] public class MyMod : BaseUnityPlugin {     public const string PLUGIN_GUID = "your_name.your_mod_id";     public const string PLUGIN_NAME = "Your Mod's Name";     public const string PLUGIN_VERSION = "1.0.0";     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         // Whenever Player.Update gets called by the game, it takes a detour into your code here instead. // Do anything that you need to happen when the player updates in here.         orig(self, eu); // Then, use this to to tell the game that it needs to run the normal code (and other mods' hooks) now. // And optionally, you can have more code here too, after orig // In general, you will want to always try to call orig // If you skip calling orig, this prevents all other mods from running their own hooks // and it also stops the game from doing the vanilla behavior.     } } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote> Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and find the Dynamic Link Library (DLL) file that it has compiled to. You then need to: # Create a folder and JSON for your mod, as described by [[Downpour Reference/Mod Directories]], and # Copy your mod DLL to a <code>plugins</code> folder within your mod's folder, as described by [[Downpour Reference/BepInEx Files]]. # Run the game and enable your mod by clicking on its name in the mod list in the Remix menu. Click the Apply Mods button. #* At time of writing, Rain World Remix does not support hot reloading of code mods, so the game needs to be restarted to apply your mod. == Enums == Due to their abundance in Rain World's code and their general usefulness in state machines, it's very possible that at some point you'll want to add your own value to an enum. To do that, you can use [[Downpour Reference/ExtEnum]]. == Advanced Techniques == === IL Hooking === IL hooking can be used to modify the Intermediate Language (IL) instructions of the game at runtime. This allows advanced editing of individual instructions within the game code. Risk of Thunder's guide to IL hooking can be found [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ here]. === RuntimeDetour === RuntimeDetour can be used to hook methods not covered by HOOKS-Assembly-CSharp.dll, as well as property getters and setters. A brief guide can be found on the [[MonoMod RuntimeDetour]] page. MonoMod's RuntimeDetour guide can be found [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md here]. === Harmony Patching === Harmony patching is a form of runtime patching. The HarmonyX wiki can be found [https://github.com/BepInEx/HarmonyX/wiki here]. [[Category:Code Mods]] b5b935777ae5ed8609e04be0792c294ad7be773c 543 542 2023-08-30T02:48:17Z Roonaloo 266 /* Step 1 - The project */ wikitext text/x-wiki BepInPlugins are the predominant form for Rain World code mods. They are a form of game mod native to [[BepInEx]]. They are not compatible with [[Partiality]]. == Creating a BepInPlugin == === Prerequisites === Before you will be able to make a mod, you need the following: * Beginner knowledge of C#, such that you are comfortable with your current level of skill. ** If you understand the concept of object oriented programming as well as main C# elements such as methods, fields, properties, events, and delegates, you should be set to go. ** Unity knowledge is optional, but useful for advanced modding. Unlike other BepInEx-modded games, Rain World's ties into Unity are sparse due to the use of the Futile engine wrapper, thus the knowledge is not required. * Entry-level skills in reverse engineering, using tools like [https://github.com/dnSpy/dnSpy dnSpy] (or any other .NET decompiler of your choosing). * A .NET programming environment. You can view feasible options here: https://dotnet.microsoft.com/en-us/platform/tools ** Windows users will want Visual Studio (''not'' Visual Studio Code, they are similar but not the same!) * .NET Framework 4.8 '''Developer Pack''' (not runtime!) which you can download here: https://dotnet.microsoft.com/en-us/download/dotnet-framework/net48 === Step 1 - The project === Create a new C# project with the Class Library(.net framework) template in your IDE. You will then need to [https://docs.microsoft.com/en-us/visualstudio/ide/how-to-add-or-remove-references-by-using-the-reference-manager?view=vs-2019 add some references]. It's recommended that you copy the files you need to reference to a safe location outside of the Rain World root directory before referencing them. Assuming you already have BepInEx installed and ready to go, the files (relative to the Rain World root directory) you should reference are: * <code>BepInEx/core/BepInEx.dll</code> * <code>BepInEx/plugins/HOOKS-Assembly-CSharp.dll</code> * <code>BepInEx/utils/PUBLIC-Assembly-CSharp.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.dll</code> * <code>RainWorld_Data/Managed/UnityEngine.CoreModule.dll</code> Note that certain mods may need more functionality from Unity. In the <code>RainWorld_Data/Managed</code> folder you will find DLL files prefixed with <code>UnityEngine.</code> - these are different parts of the Unity engine that allow doing different things, such as <code>UnityEngine.AssetBundleModule</code> for loading asset bundles built in the Unity editor. === Step 2 - The BepInPlugin class === This section requires care. ==== Step 2.1 - Setting up the Mod Main class ==== When you start up a project, it will have a default file in it named Class1.cs and it should be automatically open. You'll see some default code within it. Start by coming up with a class name. This is basically a way for you (and other code) to find your mod's main class. A generally acceptable naming convention is <code>ModNameMain</code>, for example, <code>SuperJumpBootsMain</code> is a sensible hypothetical name. If you are using Visual Studio, click on the class's name in code (Class1) and hold Left Ctrl, then press the R key twice. This will open the rename prompt, which will automatically edit every single piece of code that refers to that class, and it will also rename the file for you. Once this is done, your class needs to extend <code>BaseUnityPlugin</code>. You should also make a private method named <code>OnEnable</code>. Once that is done, it should look a bit like this: <syntaxhighlight lang="csharp"> namespace YourMod { public class ModNameMain : BaseUnityPlugin { private void OnEnable() { // Some modders also opt to use Awake() instead of OnEnable() - if you see that, it functions roughly the same. } } } </syntaxhighlight> If you are familiar with Unity development, <code>BepInPlugin</code> is a <code>MonoBehaviour</code> and all message methods are available to you. If you don't know what this means, that's okay. ==== Step 2.2 - Setting up the assembly ==== First, we need to declare a preliminary attribute on the assembly itself to prevent errors. To do this, view your Solution Explorer (it's on the right, where your files are listed in Visual Studio) and open the "Properties" object. Open AssemblyInfo.cs <br/> [[File:properties.png|frameless|The AssemblyInfo.cs file is located within the Properties object.]]<br/> ''An example from the Superstructure Fuse Fix mod.'' At the top of AssemblyInfo.cs, paste this line. You should see other lines starting with <code>using</code> to put it below. <syntaxhighlight lang="csharp"> using System.Security.Permissions; </syntaxhighlight> And then at the bottom of the file, paste this code: <syntaxhighlight lang="csharp"> #pragma warning disable CS0618 // SecurityAction.RequestMinimum is obsolete. However, this does not apply to the mod, which still needs it. Suppress the warning indicating that it is obsolete. [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] #pragma warning restore CS0618 </syntaxhighlight> Save AssemblyInfo.cs and close it, that is all that needs to be done with that file. Return to <code>ModNameMain.cs</code> (or Class1.cs, if you didn't rename it, which you should do now). ==== Step 2.3 - Setting up the mod's information ==== Now, you need to apply the appropriate attributes to your mod class. The most important of these is the <code>BepInPlugin</code> attribute, as it is responsible for storing your mod's unique ID, display name, and version. Please note that there are certain guidelines to follow when coming up with data for your mod: * Your plugin GUID ''must'' be unique, so that it does not clash with anyone else's mod. A great way to do this is following a format like <code>your_name.mod_id</code>. If it is not unique, it will break both your mod '''and''' the other person's mod, if they are both installed. * ''Match your plugin GUID with the mod ID you made for modinfo.json - they should be identical''. This ensures that other modders have an easily accessible way to find your mod's ID. * Once you decide on a GUID, ''do not change it after you release your mod''. This can wreak havoc on any mods that depend on yours! You '''can''' replace the display name at any time, just not the GUID. To declare these, start by making three <code>public const string</code> fields in your class. Use them in the <code>BepInPlugin</code> constructor. Some mods use dependencies, for example, SlugBase and RegionKit are two very popular choices. '''Not only do you need to add these dependencies to your modinfo.json, but you also need to add them to your mod's code!''' If you forget to do this, there is a chance your mod could load ''before'' a mod that you require, which means its code hasn't loaded yet. This will cause the game to crash on startup, or cause the mod to error out and do nothing. To register a dependency in your code, use the <code>BepInDependency</code> attribute. When you put this all together, it should look like this: <syntaxhighlight lang="csharp"> using BepInEx; namespace SomeMod { // There are two types of dependencies: // 1. BepInDependency.DependencyFlags.HardDependency - The other mod *MUST* be installed, and your mod cannot run without it. This ensures their mod loads before yours, preventing errors. // 2. BepInDependency.DependencyFlags.SoftDependency - The other mod doesn't need to be installed, but if it is, it should load before yours. [BepInDependency("author.some_other_mods_guid", BepInDependency.DependencyFlags.HardDependency)] // Of course, you should erase the line above. It's just an example. // As mentioned before, if the other modder uses constant strings, you can do something like this instead: // [BepInDependency(SomeOtherModMain.PLUGIN_GUID, BepInDependency.DependencyFlags.HardDependency)] // In general, it is considered bad form to directly put strings into the constructor of the BepInPlugin attribute. // By creating const string fields, other mods that depend on yours can import your mod's DLL file, and then their code can actually directly reference the data you put here! // This saves your fellow modders a lot of time and headache, and could potentially save you in the future too.     [BepInPlugin(PLUGIN_GUID, PLUGIN_NAME, PLUGIN_VERSION)]     public class MyModName : BaseUnityPlugin     {         public const string PLUGIN_GUID = "your_name.your_mod_id"; // This should be the same as the id in modinfo.json!         public const string PLUGIN_NAME = "Your Mod's Name"; // This should be a human-readable version of your mod's name. This is used for log files and also displaying which mods get loaded. In general, it's a good idea to match this with your modinfo.json as well.         public const string PLUGIN_VERSION = "1.0.0"; // This follows semantic versioning. For more information, see https://semver.org/ - again, match what you have in modinfo.json // It should go without saying, but for this to benefit other modders, the class *and* these const strings must be public. private void OnEnable() { }     } } </syntaxhighlight> Once this is done, your code is fully prepared to facilitate everything you need for your mod to work! === Step 3 - Hooking === Hooks allow you to execute your own code when the method you are hooking from the game code is called. Hooking is the recommended way of modifying the functionality of the game, as your hooks will allow the hooks of other mods and the game code itself to run as expected (presuming you don't do something that they don't expect). From your class constructor or <code>OnEnable</code>, you can subscribe to the event that triggers when a method from the Rain World code is called. If you don't know how events work, here's a quick example: <syntaxhighlight lang="csharp"> namespace SomeMod { [BepInPlugin(PLUGIN_GUID, PLUGIN_NAME, PLUGIN_VERSION)] public class MyMod : BaseUnityPlugin {     public const string PLUGIN_GUID = "your_name.your_mod_id";     public const string PLUGIN_NAME = "Your Mod's Name";     public const string PLUGIN_VERSION = "1.0.0";     public void OnEnable()     {         /* This is called when the mod is loaded. */         // subscribe your PlayerUpdateHook to the Player.Update method from the game         On.Player.Update += PlayerUpdateHook;     }     void PlayerUpdateHook(On.Player.orig_Update orig, Player self, bool eu)     {         // Whenever Player.Update gets called by the game, it takes a detour into your code here instead. // Do anything that you need to happen when the player updates in here.         orig(self, eu); // Then, use this to to tell the game that it needs to run the normal code (and other mods' hooks) now. // And optionally, you can have more code here too, after orig // In general, you will want to always try to call orig // If you skip calling orig, this prevents all other mods from running their own hooks // and it also stops the game from doing the vanilla behavior.     } } } </syntaxhighlight> Note that our hook there - <code>PlayerUpdateHook</code> - takes the orig method, the <code>Player</code> object whose <code>Update</code> method was called (since <code>Player.Update</code> is not static), and the parameters taken by the original method. If you have many hooks consider organising them, perhaps into separate classes. <blockquote>''"Where can I find these magical and elusive Rain World methods?"''</blockquote> Since the source code for Rain World is not public, one must use a decompiler such as [https://github.com/dnSpy/dnSpy/releases/latest DnSpy] or [https://marketplace.visualstudio.com/items?itemName=SharpDevelopTeam.ILSpy ILSpy] to look through the <code>Assembly-CSharp.dll</code> file. '''Reminder''': you should never distribute significant portions of the game's code or the binaries, or that of any closed source mods unless you have explicit permission to do so from the mod author. Pay attention to licenses on public repositories too - see [https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository GitHub's guide to code licensing] and if in doubt ask the author. === Testing your code === Build your code and find the Dynamic Link Library (DLL) file that it has compiled to. You then need to: # Create a folder and JSON for your mod, as described by [[Downpour Reference/Mod Directories]], and # Copy your mod DLL to a <code>plugins</code> folder within your mod's folder, as described by [[Downpour Reference/BepInEx Files]]. # Run the game and enable your mod by clicking on its name in the mod list in the Remix menu. Click the Apply Mods button. #* At time of writing, Rain World Remix does not support hot reloading of code mods, so the game needs to be restarted to apply your mod. == Enums == Due to their abundance in Rain World's code and their general usefulness in state machines, it's very possible that at some point you'll want to add your own value to an enum. To do that, you can use [[Downpour Reference/ExtEnum]]. == Advanced Techniques == === IL Hooking === IL hooking can be used to modify the Intermediate Language (IL) instructions of the game at runtime. This allows advanced editing of individual instructions within the game code. Risk of Thunder's guide to IL hooking can be found [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ here]. === RuntimeDetour === RuntimeDetour can be used to hook methods not covered by HOOKS-Assembly-CSharp.dll, as well as property getters and setters. A brief guide can be found on the [[MonoMod RuntimeDetour]] page. MonoMod's RuntimeDetour guide can be found [https://github.com/MonoMod/MonoMod/blob/master/README-RuntimeDetour.md here]. === Harmony Patching === Harmony patching is a form of runtime patching. The HarmonyX wiki can be found [https://github.com/BepInEx/HarmonyX/wiki here]. [[Category:Code Mods]] 067eceb34b1858f712e392768a62f6779d66fe0e User:Lurzard 2 208 540 2023-07-24T21:58:10Z Lurzard 227 create user page wikitext text/x-wiki da39a3ee5e6b4b0d3255bfef95601890afd80709 Getting Started 0 177 544 405 2023-09-12T20:01:43Z Timofey26 282 fixed misleading(rwe+ a long time ago had comms material and effects support, thanks to slime_cubed) wikitext text/x-wiki {{Cleanup}} == "I want to make a code mod!" == === "I'm new to coding." === Rainworld is coded in C#. You will want a good understanding of it, along with understanding how object orientated programming works. For specific resources on learning C#, see [[Learning_C_Sharp|Learning C#]] === "I understand C#, How do I make mods?" === In general, mods are made by 'hooking' into Rainworld's existing methods, and putting your own code either before or after those methods. For getting started with hooking and Bepin plugins, see [[BepInPlugins]]<br> You will need to download either [https://github.com/dnSpy/dnSpy dnSpy] or [https://github.com/icsharpcode/ILSpy ILSpy]. Both decompile the game's code so you can read it. ILspy is better at decompiling than dnSpy, but has a worse interface.<br> You can find Rainworld's code in <code>Rain World\RainWorld_Data\Managed\Assembly-CSharp.dll</code>. Simply open this file up with either program. While a little outdated, [https://www.youtube.com/playlist?list=PLuHyVLkKIJi3P6xu-V3aRTAlwWpdDKxSa Henpe's modding guides] are very useful at explaining how the game works. Video 1 is very outdated, however. When starting out, you'll want to use a mod template to setup your plugin. For example, Noir's mod templates: * [https://github.com/NoirCatto/RainWorldRemix/tree/master/Templates/TemplateMod Template without options menu] * [https://github.com/NoirCatto/RainWorldRemix/tree/master/Templates/TemplateModWithOptions Template with options menu] You will need to add dependencies to your file. You can do this by right clicking 'dependencies' -> Add Project Reference -> Browse -> then find the .dll files in your Rainworld install (or if you’re depending on a mod, in your Workshop files.) Generally you will want to always depend on <code>Rain World\BepInEx\utils\PUBLIC-Assembly-CSharp.dll</code> and <code>Rain World\BepInEx\plugins\HOOKS-Assembly-CSharp.dll</code>. === "I want to make a custom slugcat!" === Custom slugcats are made easy by using [https://steamcommunity.com/workshop/filedetails/?id=2933196558 Slugbase]. It has its own set of tutorials and documentation on its [https://slimecubed.github.io/slugbase/ Github page], along with a [https://slimecubed.github.io/slugbase/articles/template.html template] to get started. === "I want to make custom sprites for DMS!" === DMS sprites work very similarly to FancySlugCat sprites. Mehri has made a [https://steamcommunity.com/sharedfiles/filedetails/?id=2902555797 guide] on the steam community explaining how to create them. === "I want to make a custom lizard/variant of any creature!" === Fisobs is used in creating custom creatures. It is made primarily for unique creatures but can also be used to create variants. [https://github.com/Dual-Iron/fisobs/tree/master/examples Fisobs’ examples of a custom creature and item]<br> LB has provided an example of a working Lizard variant to examine, downloadable [https://cdn.discordapp.com/attachments/1083483097145819348/1087296693684408380/Undersea_-_Copy.zip here].<br> In general, you want to have Fisobs return the creature/ai/state of what you are making a variant of, and then hook into that creature's methods to change it based on if that creature's template.type is your custom variant's template. For those making custom lizards based on a lizard customizer lizard, BreedParams is where most of your lizard customizer stats will go. Lizard customizer is also '''NOT compatible''' with Fisobs custom lizards! == "I want to make levels/regions!" == General good advice is to study existing rooms! Your installation of the level editor should come with the project files of all the base game rooms, you can open these up to study. Look at how the tiles and materials were done, along with the general flow of the level. You can download the Official Level Editor [https://ln5.sync.com/dl/2c28693d0/q2b2zh8m-vdmsuwyj-5w3efg5c-gvhg7ben/view/default/11921401610004 here]. An in depth guide to starting with the level editor can be found at [[Region_From_The_Ground_Up|Region From The Ground Up]] Kaeporo has created a video guide to using the level editor, [https://youtu.be/YQ0DO-fmPCE available here]. When you want to put your levels in game, you will put your rendered level files (a .txt and .pngs for each camera) in: * <code>mods\[yourmod'sname]\levels</code> for Arena levels. * <code>mods\[yourmod'sname]\world\[regionacronymn]_rooms</code> for region rooms. For regions you will also need a <code>world_[region acronym].txt</code> in \mods\[yourmod'sname]\world\[regionacronymn]<br> For example, a region with the acronym <code>GM</code> would have a <code>world_GM.txt</code> in <code>\world\GM</code>, and its rooms would be in <code>\world\GM-rooms</code> Once in game, you will likely want to change the palette and add effects and objects into the room. You can use Dev Tools to do this. First you need to enable it in the remix menu, then once in game you can enable it by pressing <code>O</code>. The main Dev Tools menu is opened by pressing <code>H</code>. For more info on the devtool's menu, see [[Dev_Tools|Dev Tools]] === Additional Resources === There is also the [https://drive.google.com/drive/folders/1TlriD672VL00PkJlx5jpP-b5E5YwctKn Community Level Editor]. You install it on top of your official level editor. It will add on community materials and effects, along with making the level editor more stable and including reminders for the keybinds! [https://github.com/timofey260/RWE-Plus Timofey's RWE+] is an alternative level editor. It renders using Drizzle, a custom renderer. RWE+ has a more user friendly interface, and Drizzle is a much faster renderer than the normal renderer, with community effects and materials in it. Solar has collected a repository of community made tiles and props for the Level editor, along with the level project files of many modded regions. [https://github.com/solaristheworstcatever/Modded-Regions-Starter-Pack Github Link]. Bro has created a world editor program to make it easier to setup a region's connections, spawns, and maps, [https://github.com/Bro748/World-Editor/releases/tag/MSC-1.00 downloadable from Github here]. <br> [https://steamcommunity.com/sharedfiles/filedetails/?id=2920439476 Regionkit] is a dependency that contains many useful objects and settings such as custom shelter behaviours, custom decals, animated machinery, particles systems etc. These can be accessed primarily through Dev Tools. 11ad897467f8a020ee069a89540abd2267c60c8d Remix Menu 0 186 545 451 2023-09-12T20:02:30Z Timofey26 282 spelling mistake wikitext text/x-wiki {{Cleanup}} {{todo}} Remix uses ConfigMachine for it's option interfaces. == Creating an options menu: == Options menus are inherited from OptionInterface <syntaxhighlight lang="csharp"> public class OptionsMenu : OptionInterface { } </syntaxhighlight> You will want to store your configurable variables as: <code> public readonly Configurable<TYPE> NAME; </code>, then initialize them in the constructor: <syntaxhighlight lang="csharp"> public OptionsMenu(Plugin plugin) { NAME = this.config.Bind<TYPE>("KEY", DEFAULTVALUE); } </syntaxhighlight> '''IMPORTANT''': Config entry keys should only contain Latin letters and underscores! Putting an unexpected character will throw an exception === Setting up the interface === In your <code>Initialize()</code> method: <syntaxhighlight lang="csharp"> var opTab = new OpTab(this, "TABNAME"); //Create a tab. this.Tabs = new OpTab[] { opTab //Add the tab into your list of tabs. }; UIelement[] UIarrayOptions = new UIelement[] //create an array of ui elements { new OpLabel(10f, 550f, "Options", true), //Creates a label at 10,550 with big text saying "Options" }; opTab.AddItems(UIarrayOptions); //adds the elements to the tab </syntaxhighlight> A list of all UI elements in ConfigMachine is available [[ConfigMachine/Provided_Elements|here]]. === Connecting your options interface === You will need to setup an instance of your optionsmenu in the main plugin: <syntaxhighlight lang="csharp"> private OptionsMenu options; public Plugin() { options = new OptionsMenu(this); } </syntaxhighlight> Then in your OnModsInit hook, add a call to register your interface: <syntaxhighlight lang="csharp"> public Hook_OnModsInit(On.RainWorld.orig_OnModsInit orig, RainWorld self) { orig(self); try { MachineConnector.SetRegisteredOI("PLUGINID", options); } catch (Exception ex) { /* make sure to error-proof your hook, otherwise the game may break in a hard-to-track way and other mods may stop working */ } } </syntaxhighlight> <br> Plugin id must be '''EXACT''' to the id specified in your mod's <code>ModInfo.json</code> You can retrieve the values from the option menu simply by doing <code> options.name.value </code>. <br> For player specific values you can have the option value as an array, and simply do <code> options.name[self.playerNumber].value to return that player's version. 050985339ea487c88442c3a97c112c47eb488126 Learning C Sharp 0 174 548 381 2023-09-17T02:32:01Z Pommegranite 287 wikitext text/x-wiki C# is a general-purpose programming language popular in game development. More information about the language can be found [https://en.wikipedia.org/wiki/C%20Sharp%20(programming%20language) on its Wikipedia page]. Rain World's code is written in C#. As per the standard C# development life cycle, each release of the game is compiled into .NET's Common Intermediate Language (CIL) which is stored in Dynamic Link Library (DLL) files. To read an approximation of the game's code, a .NET decompiler is used to decompile the CIL into C# (or sometimes to view the IL when IL editing). As such, code mods are also written in C#, and so an understanding of C# is '''essential''' for code modding. == Beginner Guides == * [https://www.w3schools.com/cs/index.php w3schools] - if you're new to programming * [https://learnxinyminutes.com/docs/csharp/ Learn X in Y minutes] - if some experience in another language and OOP * [https://dotnet.microsoft.com/en-us/learn/csharp Microsoft: Learn C#] - more comprehensive * {https://www.youtube.com/@BroCodez/playlists} - Bro Code has comprehensive, easy to understand playlists for lots of programming languages. If you're having difficulty getting starting with c#, pairing his videos with the hands on approach of w3schools is a great way to go. == Important Topics == * [https://www.geeksforgeeks.org/scope-of-variables-in-c-sharp/ GeeksForGeeks: Scope in C#] * [https://isaaccomputerscience.org/topics/object_oriented_programming Isaac Computer Science: Object-Oriented Programming (OOP)] == Other == * [https://isaaccomputerscience.org/topics/a_level?examBoard=all&stage=all#aqa Isaac Computer Science - AQA A-level Computer Science] ** Covers content for the AQA A-level Computer Science (UK exam) specification. It's not C# specific, but chapters 4.1 to 4.3 (and to some extent 4.4) are nice resources for getting to grips with programming. [[Category:Code Mods]] d95acfaee992b8fa59b41daad3fab194f12977d0 549 548 2023-09-17T02:32:43Z Pommegranite 287 wikitext text/x-wiki C# is a general-purpose programming language popular in game development. More information about the language can be found [https://en.wikipedia.org/wiki/C%20Sharp%20(programming%20language) on its Wikipedia page]. Rain World's code is written in C#. As per the standard C# development life cycle, each release of the game is compiled into .NET's Common Intermediate Language (CIL) which is stored in Dynamic Link Library (DLL) files. To read an approximation of the game's code, a .NET decompiler is used to decompile the CIL into C# (or sometimes to view the IL when IL editing). As such, code mods are also written in C#, and so an understanding of C# is '''essential''' for code modding. == Beginner Guides == * [https://www.w3schools.com/cs/index.php w3schools] - if you're new to programming * [https://learnxinyminutes.com/docs/csharp/ Learn X in Y minutes] - if some experience in another language and OOP * [https://dotnet.microsoft.com/en-us/learn/csharp Microsoft: Learn C#] - more comprehensive * [https://www.youtube.com/@BroCodez/playlists] - Bro Code has comprehensive, easy to understand playlists for lots of programming languages. If you're having difficulty getting starting with c#, pairing his videos with the hands on approach of w3schools is a great way to go. == Important Topics == * [https://www.geeksforgeeks.org/scope-of-variables-in-c-sharp/ GeeksForGeeks: Scope in C#] * [https://isaaccomputerscience.org/topics/object_oriented_programming Isaac Computer Science: Object-Oriented Programming (OOP)] == Other == * [https://isaaccomputerscience.org/topics/a_level?examBoard=all&stage=all#aqa Isaac Computer Science - AQA A-level Computer Science] ** Covers content for the AQA A-level Computer Science (UK exam) specification. It's not C# specific, but chapters 4.1 to 4.3 (and to some extent 4.4) are nice resources for getting to grips with programming. [[Category:Code Mods]] 03ce9c2ff37aec2bc41c2ddbb3409456d15529aa 550 549 2023-09-17T02:33:42Z Pommegranite 287 wikitext text/x-wiki C# is a general-purpose programming language popular in game development. More information about the language can be found [https://en.wikipedia.org/wiki/C%20Sharp%20(programming%20language) on its Wikipedia page]. Rain World's code is written in C#. As per the standard C# development life cycle, each release of the game is compiled into .NET's Common Intermediate Language (CIL) which is stored in Dynamic Link Library (DLL) files. To read an approximation of the game's code, a .NET decompiler is used to decompile the CIL into C# (or sometimes to view the IL when IL editing). As such, code mods are also written in C#, and so an understanding of C# is '''essential''' for code modding. == Beginner Guides == * [https://www.w3schools.com/cs/index.php w3schools] - if you're new to programming * [https://learnxinyminutes.com/docs/csharp/ Learn X in Y minutes] - if some experience in another language and OOP * [https://dotnet.microsoft.com/en-us/learn/csharp Microsoft: Learn C#] - more comprehensive * [https://www.youtube.com/@BroCodez/playlists Bro Code Programming Tutorials] - Bro Code has comprehensive, easy to understand playlists for lots of programming languages. If you're having difficulty getting starting with c#, pairing his videos with the hands on approach of w3schools is a great way to go. == Important Topics == * [https://www.geeksforgeeks.org/scope-of-variables-in-c-sharp/ GeeksForGeeks: Scope in C#] * [https://isaaccomputerscience.org/topics/object_oriented_programming Isaac Computer Science: Object-Oriented Programming (OOP)] == Other == * [https://isaaccomputerscience.org/topics/a_level?examBoard=all&stage=all#aqa Isaac Computer Science - AQA A-level Computer Science] ** Covers content for the AQA A-level Computer Science (UK exam) specification. It's not C# specific, but chapters 4.1 to 4.3 (and to some extent 4.4) are nice resources for getting to grips with programming. [[Category:Code Mods]] bc20122584e1377e745b85243991607610afe793 551 550 2023-09-17T02:34:24Z Pommegranite 287 wikitext text/x-wiki C# is a general-purpose programming language popular in game development. More information about the language can be found [https://en.wikipedia.org/wiki/C%20Sharp%20(programming%20language) on its Wikipedia page]. Rain World's code is written in C#. As per the standard C# development life cycle, each release of the game is compiled into .NET's Common Intermediate Language (CIL) which is stored in Dynamic Link Library (DLL) files. To read an approximation of the game's code, a .NET decompiler is used to decompile the CIL into C# (or sometimes to view the IL when IL editing). As such, code mods are also written in C#, and so an understanding of C# is '''essential''' for code modding. == Beginner Guides == * [https://www.w3schools.com/cs/index.php w3schools] - if you're new to programming * [https://learnxinyminutes.com/docs/csharp Learn X in Y minutes] - if some experience in another language and OOP * [https://dotnet.microsoft.com/en-us/learn/csharp Microsoft: Learn C#] - more comprehensive * [https://www.youtube.com/@BroCodez/playlists Bro Code Programming Tutorials] - Bro Code has comprehensive, easy to understand playlists for lots of programming languages. If you're having difficulty getting starting with c#, pairing his videos with the hands on approach of w3schools is a great way to go. == Important Topics == * [https://www.geeksforgeeks.org/scope-of-variables-in-c-sharp/ GeeksForGeeks: Scope in C#] * [https://isaaccomputerscience.org/topics/object_oriented_programming Isaac Computer Science: Object-Oriented Programming (OOP)] == Other == * [https://isaaccomputerscience.org/topics/a_level?examBoard=all&stage=all#aqa Isaac Computer Science - AQA A-level Computer Science] ** Covers content for the AQA A-level Computer Science (UK exam) specification. It's not C# specific, but chapters 4.1 to 4.3 (and to some extent 4.4) are nice resources for getting to grips with programming. [[Category:Code Mods]] 3378e0314d1a475f3881715bd28115058cb28953 User:Alphappy/Live/IL hooking 2 209 552 2023-10-04T08:14:02Z Alphappy 121 new page wikitext text/x-wiki '''IL hooking''', or '''intermediate-language hooking''', is an alternative to standard event hooking that allows for injection of arbitrary instructions within a method. ==Prerequisites== It is assumed that you fully understand how to use a standard event hook (<code>On</code>) as described at [[BepInPlugins]]. Additionally, it will be helpful to understand the concept of an [[w:Stack (abstract data type)|evaluation stack]], which is how objects are stored at the intermediate level. [[w:High-level programming language|High-level programming languages]] like C# abstract away the evaluation stack and allow for the more human-friendly use of named variables. This will be a little more complicated in IL. It is highly recommended to have a convenient way to view the IL instructions of Rain World's code. dnSpy can do this - right-click a line of code, and select ''Edit IL Instructions...'' We will cover how to interpret this information later. You will need to add several additional references to your project for IL hooking to work: *<code>Mono.Cecil.dll</code> *<code>Mono.Cecil.Mdb.dll</code> *<code>Mono.Cecil.Pdb.dll</code> *<code>Mono.Cecil.Rocks.dll</code> *<code>MonoMod.Common.dll</code> *<code>MonoMod.RuntimeDetour.dll</code> *<code>MonoMod.Utils.dll</code> These are normally in <code>Steam\steamapps\common\Rain World\RainWorld_Data\Managed</code> (although it is again recommended to copy them somewhere else first). This guide is intended to be self-sufficient, but see also [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ Risk of Thunder's guide to IL hooking] for another perspective and more examples. Everything in this guide is tested with Visual Studio 2022 17.7.0. ==Overview== Like standard event hooking, IL hooking targets a specific method in Rain World's assembly. There are a few key differences: *A standard event hook receives references to the original method <code>orig</code> and every argument that it would have received (including <code>this</code> if non-static, which the hook receives as <code>self</code> by default). An IL hook receives only an <code>ILContext</code> which is used to navigate the method's IL instructions. *The code you write in a standard event hook is run every time the game calls the hooked method (assuming no other mods hook that method and forgo the <code>orig</code> call). In an IL hook, the code you write is run only once when the mod is initialized, but the effect of this code is to essentially modify the original method directly. *A standard event hook can essentially only cause changes at the beginning or end of an existing method. An IL hook can cause changes inside a method. ==Procedure== As an example, we're going to hook <code>Leech.Attached</code> to prevent Jungle Leeches from draining Slugcat's food. As the relevant code is in the middle of the method, a standard event hook won't work (at least not easily). ===Step 1: Create an IL hook=== IL hooks are created similarly to standard event hooks. First, we must import a couple of things: <syntaxhighlight lang="csharp"> using Mono.Cecil.Cil; using MonoMod.Cil; </syntaxhighlight> Next, you can auto-generate the hooking method just as you would with a standard event hook. Pressing TAB twice after <code>+=</code> will create the hooking method automatically. <syntaxhighlight lang="csharp"> private void OnEnable() { IL.Leech.Attached += Leech_Attached; } private void Leech_Attached(ILContext il) { throw new NotImplementedException(); } </syntaxhighlight> You will also need to instantiate the cursor: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); } </syntaxhighlight> ===Step 2: Determine what to modify=== Before we can proceed, we need to know how to actually modify the method to get the effect we want. In <code>Leech.Attached</code>, the method checks whether the Leech in question is a Jungle Leech, then whether the creature it is attached to is a <code>Player</code> (Slugcat). Ultimately, we want the method to ''not'' check whether the creature is a <code>Player</code> and just skip the entire following block of code. Viewing the IL for this method reveals the following IL: <pre> 270 02FC ldarg.0 271 02FD ldfld bool Leech::jungleLeech 272 0302 brfalse 414 (050D) ldarg.0 273 0307 ldloc.0 274 0308 callvirt instance class PhysicalObject BodyChunk::get_owner() 275 030D isinst Player 276 0312 brfalse 340 (03F5) ldloc.0 </pre> Each row is an ''instruction''. The first column is the ''index'' of the instruction. The third column is the ''OpCode'' for that instruction, and the final column is the ''operand''. These instructions mean the following: {| class="wikitable" ! Index ! OpCode ! Operand ! Meaning |- | 270 | <code>ldarg.0</code> | | Put argument 0 on the evaluation stack. In a non-static class method, argument 0 is always a reference to <code>this</code>. |- | 271 | <code>ldfld</code> | <code>bool Leech::jungleLeech</code> | Pop an item off the stack, access its <code>jungleLeech</code> field, and put that <code>bool</code> on the stack. |- | 272 | <code>brfalse</code> | <code>414</code> | Pop an item off the stack. If it is false, go to the instruction at index 414. |- | 273 | <code>ldloc.0</code> | | Put local variable 0 on the stack (the first local variable defined in this method). This is the <code>BodyChunk</code> from a couple lines ago. |- | 274 | <code>callvirt</code> | <code>instance class PhysicalObject BodyChunk::get_owner()</code> | Pop an item off the stack, and call its <code>get_owner</code> property getter. Put the <code>PhysicalObject</code> instance that this returns on the stack. |- | 275 | <code>isinst</code> | <code>Player</code> | Pop an item off the stack. Put a <code>bool</code> on the stack corresponding to whether it is an instance of <code>Player</code>. |- | 276 | <code>brfalse</code> | <code>340</code> | Pop an item off the stack. If it is false, go to the instruction at index 340. |} Instructions 270 through 272 correspond to <code>if (this.JungleLeech)</code>, and instructions 273 through 275 correspond to <code>bodyChunk.owner is Player</code>. Because the conditional uses short-circuiting <code>&&</code> here, instruction 276 immediately skips if <code>bodyChunk.owner is Player</code> is <code>false</code>. We want to have the code not even bother with checking if it's a <code>Player</code> and skip the following block immediately, which we will do in the next sections. ===Step 3: Find the instructions of interest=== While we ''could'' tell the cursor to move directly to the index of the instructions we want to modify, that won't work reliably if any other mod IL hooks this method and changes the number of instructions. Instead, the better procedure is to ''search'' for a sequence of instructions. How many instructions should be included in this sequence is subjective. Too few, and there's a chance your hook will land somewhere it shouldn't; too many, and there's a chance another hook will modify code inside what you are trying to match, and your hook matches nothing and fails. In this example, matching instructions 270 through 276 should suffice. We tell our <code>ILCursor</code> to search for a specific sequence of instructions with <code>GotoNext</code>: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); } </syntaxhighlight> This will tell the cursor to find an <code>ldarg.0</code> instruction, followed by a <code>ldfld</code> instruction with <code>jungleLeech</code> as the operand, et cetera. Crucially, it must find all seven of these instructions in order with no gaps. If successful, this will place the cursor at index 270. ===Step 4: Modify the instructions=== From earlier, we want to insert instructions to make the method skip checking whether <code>bodyChunk.owner is Player</code> and the following block. This just involves inserting an unconditional branch instruction. However, we have to tell it ''where'' to branch to, so we have one extra step of grabbing a reference to the instruction we want to branch to. Because we told the cursor to look for the entire sequence of 7 instructions, we can be sure they all exist here, and we don't have to use <code>GotoNext</code> to search again. We do the following to achieve this: Jump to the instruction that will skip the food drain code (276). <syntaxhighlight lang="csharp">c.Index += 6;</syntaxhighlight> Grab the operand of this instruction and store it locally. The operand of a branch instruction is always another <code>ILLabel</code> which points to the instruction of interest. <syntaxhighlight lang="csharp">ILLabel inst = (ILLabel)cursor.Next.Operand;</syntaxhighlight> Jump to just before the method is checking whether <code>bodyChunk.owner is Player</code> (273). <syntaxhighlight lang="csharp">c.Index -= 3;</syntaxhighlight> ''Emit'' an instruction to branch unconditionally to the instruction we referenced earlier, skipping the food drain block. <syntaxhighlight lang="csharp">cursor.Emit(OpCodes.Br, inst);</syntaxhighlight> This new instruction exists between instructions 272 and 273 because the cursor's <code>Index</code> at the time was 273. This is what our hooking method looks like now: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Br, inst); } </syntaxhighlight> What we've effectively done is changed this piece of <code>Leech.Attached</code>: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && Random.value < (((bodyChunk.owner as Player).stun > 40) ? 0.009f : 0.002f)) { ... } </syntaxhighlight> into this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (false && bodyChunk.owner is Player && Random.value < (((bodyChunk.owner as Player).stun > 40) ? 0.009f : 0.002f)) { ... } </syntaxhighlight> We've now achieved exactly what we wanted but, for the sake of example, we will now attach this behavior to the value of a <code>Configurable<bool></code> (e.g., from a Remix <code>OptionInterface</code>) to illustrate how to reference things in the current context for the IL context. ===Step 5: Use a delegate to access the current context from the IL context=== We'll assume that you have already set up a <code>Configurable<bool></code> and an <code>OptionInterface</code> to allow toggling it, and that it is stored in the static field <code>Options.foodDrainToggle</code>. Although it would be possible to reference <code>Options.foodDrainToggle</code> with some specific sequence of instructions, we can give the <code>ILCursor</code> a ''delegate'' that we write in the current context instead, and it will store that delegate to use again in the IL context when the method is actually run. In this case, it would look like: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); </syntaxhighlight> The type argument indicates that the delegate takes no arguments (and thus removes nothing from the evaluation stack), but returns a boolean (which is then put on the stack). This needs to be placed just before the branch instruction we inserted earlier, which also needs to be changed to a conditional branch (<code>brfalse</code>) so that it actually checks the boolean we just put on the stack. Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> Note that when we emit, the cursor also moves forward, so we don't have to bump up the <code>Index</code> before inserting the next instruction. The equivalent C# code now looks like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && Random.value < (((bodyChunk.owner as Player).stun > 40) ? 0.009f : 0.002f)) { ... } </syntaxhighlight> ===Step 6: Use a delegate to access the IL context from the current context=== We can put just about anything we want into the delegate. If we wanted to have Slugcat be [https://rainworld.miraheze.org/wiki/User:Alphappy/Live/Slowing slowed] while a Jungle Leech is attached, we could change our delegate to take in the <code>BodyChunk</code> that the original method already stored as a local: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); </syntaxhighlight> Note that this delegate ''does'' take one input, which we must put on the stack before calling this delegate. Fortunately, because it's a local we're using, that is very simple: <syntaxhighlight lang="csharp"> cursor.Emit(OpCodes.Ldloc, 0); </syntaxhighlight> Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Ldloc, 0); cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> The equivalent C# code now looks something like like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && Random.value < (((bodyChunk.owner as Player).stun > 40) ? 0.009f : 0.002f)) { ... } </syntaxhighlight> Worth noting that, to achieve this slowing, we could have instead inserted a delegate after the instructions corresponding to <code>bodyChunk.owner is Player</code> instead so we don't have to make that check in our delegate. In that regard, what we've done here is inefficient, but it nonetheless demonstrates how to use something currently on the evaluation stack (that is, in the IL context) in the current context. ==Notes== ===Stack balance=== If you get an exception telling you that <code>ret</code> is an invalid OpCode, you've left the stack unbalanced. The number of objects on the stack before and after a method executes must be equal. If the stack is ''unbalanced'' - that is, more things are placed on the stack than are removed for a given method, or vice versa - the IL hook will fail. It is therefore important to understand [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields how each OpCode interacts with the stack]. Most instructions pop one object, push one object, or both - but some instructions may pop or push more than one object depending on their operand. ===Printing IL=== You can print the IL to the log: <code>Debug.Log(il.ToString());</code>. This will give you the same information that dnSpy's IL viewer does, although with slightly different syntax. Crucially, you can print the IL ''after'' your cursor has made all of its changes to make sure that they are the changes you intended. c2376b943e76312b8908664e78898589c45f4de5 553 552 2023-10-04T08:27:11Z Alphappy 121 eliminate ultimately unnecessary parts of the RW code example wikitext text/x-wiki '''IL hooking''', or '''intermediate-language hooking''', is an alternative to standard event hooking that allows for injection of arbitrary instructions within a method. ==Prerequisites== It is assumed that you fully understand how to use a standard event hook (<code>On</code>) as described at [[BepInPlugins]]. Additionally, it will be helpful to understand the concept of an [[w:Stack (abstract data type)|evaluation stack]], which is how objects are stored at the intermediate level. [[w:High-level programming language|High-level programming languages]] like C# abstract away the evaluation stack and allow for the more human-friendly use of named variables. This will be a little more complicated in IL. It is highly recommended to have a convenient way to view the IL instructions of Rain World's code. dnSpy can do this - right-click a line of code, and select ''Edit IL Instructions...'' We will cover how to interpret this information later. You will need to add several additional references to your project for IL hooking to work: *<code>Mono.Cecil.dll</code> *<code>Mono.Cecil.Mdb.dll</code> *<code>Mono.Cecil.Pdb.dll</code> *<code>Mono.Cecil.Rocks.dll</code> *<code>MonoMod.Common.dll</code> *<code>MonoMod.RuntimeDetour.dll</code> *<code>MonoMod.Utils.dll</code> These are normally in <code>Steam\steamapps\common\Rain World\RainWorld_Data\Managed</code> (although it is again recommended to copy them somewhere else first). This guide is intended to be self-sufficient, but see also [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ Risk of Thunder's guide to IL hooking] for another perspective and more examples. Everything in this guide is tested with Visual Studio 2022 17.7.0. ==Overview== Like standard event hooking, IL hooking targets a specific method in Rain World's assembly. There are a few key differences: *A standard event hook receives references to the original method <code>orig</code> and every argument that it would have received (including <code>this</code> if non-static, which the hook receives as <code>self</code> by default). An IL hook receives only an <code>ILContext</code> which is used to navigate the method's IL instructions. *The code you write in a standard event hook is run every time the game calls the hooked method (assuming no other mods hook that method and forgo the <code>orig</code> call). In an IL hook, the code you write is run only once when the mod is initialized, but the effect of this code is to essentially modify the original method directly. *A standard event hook can essentially only cause changes at the beginning or end of an existing method. An IL hook can cause changes inside a method. ==Procedure== As an example, we're going to hook <code>Leech.Attached</code> to prevent Jungle Leeches from draining Slugcat's food. As the relevant code is in the middle of the method, a standard event hook won't work (at least not easily). ===Step 1: Create an IL hook=== IL hooks are created similarly to standard event hooks. First, we must import a couple of things: <syntaxhighlight lang="csharp"> using Mono.Cecil.Cil; using MonoMod.Cil; </syntaxhighlight> Next, you can auto-generate the hooking method just as you would with a standard event hook. Pressing TAB twice after <code>+=</code> will create the hooking method automatically. <syntaxhighlight lang="csharp"> private void OnEnable() { IL.Leech.Attached += Leech_Attached; } private void Leech_Attached(ILContext il) { throw new NotImplementedException(); } </syntaxhighlight> You will also need to instantiate the cursor: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); } </syntaxhighlight> ===Step 2: Determine what to modify=== Before we can proceed, we need to know how to actually modify the method to get the effect we want. In <code>Leech.Attached</code>, the method checks whether the Leech in question is a Jungle Leech, then whether the creature it is attached to is a <code>Player</code> (Slugcat). Ultimately, we want the method to ''not'' check whether the creature is a <code>Player</code> and just skip the entire following block of code. Viewing the IL for this method reveals the following IL: <pre> 270 02FC ldarg.0 271 02FD ldfld bool Leech::jungleLeech 272 0302 brfalse 414 (050D) ldarg.0 273 0307 ldloc.0 274 0308 callvirt instance class PhysicalObject BodyChunk::get_owner() 275 030D isinst Player 276 0312 brfalse 340 (03F5) ldloc.0 </pre> Each row is an ''instruction''. The first column is the ''index'' of the instruction. The third column is the ''OpCode'' for that instruction, and the final column is the ''operand''. These instructions mean the following: {| class="wikitable" ! Index ! OpCode ! Operand ! Meaning |- | 270 | <code>ldarg.0</code> | | Put argument 0 on the evaluation stack. In a non-static class method, argument 0 is always a reference to <code>this</code>. |- | 271 | <code>ldfld</code> | <code>bool Leech::jungleLeech</code> | Pop an item off the stack, access its <code>jungleLeech</code> field, and put that <code>bool</code> on the stack. |- | 272 | <code>brfalse</code> | <code>414</code> | Pop an item off the stack. If it is false, go to the instruction at index 414. |- | 273 | <code>ldloc.0</code> | | Put local variable 0 on the stack (the first local variable defined in this method). This is the <code>BodyChunk</code> from a couple lines ago. |- | 274 | <code>callvirt</code> | <code>instance class PhysicalObject BodyChunk::get_owner()</code> | Pop an item off the stack, and call its <code>get_owner</code> property getter. Put the <code>PhysicalObject</code> instance that this returns on the stack. |- | 275 | <code>isinst</code> | <code>Player</code> | Pop an item off the stack. Put a <code>bool</code> on the stack corresponding to whether it is an instance of <code>Player</code>. |- | 276 | <code>brfalse</code> | <code>340</code> | Pop an item off the stack. If it is false, go to the instruction at index 340. |} Instructions 270 through 272 correspond to <code>if (this.JungleLeech)</code>, and instructions 273 through 275 correspond to <code>bodyChunk.owner is Player</code>. Because the conditional uses short-circuiting <code>&&</code> here, instruction 276 immediately skips if <code>bodyChunk.owner is Player</code> is <code>false</code>. We want to have the code not even bother with checking if it's a <code>Player</code> and skip the following block immediately, which we will do in the next sections. ===Step 3: Find the instructions of interest=== While we ''could'' tell the cursor to move directly to the index of the instructions we want to modify, that won't work reliably if any other mod IL hooks this method and changes the number of instructions. Instead, the better procedure is to ''search'' for a sequence of instructions. How many instructions should be included in this sequence is subjective. Too few, and there's a chance your hook will land somewhere it shouldn't; too many, and there's a chance another hook will modify code inside what you are trying to match, and your hook matches nothing and fails. In this example, matching instructions 270 through 276 should suffice. We tell our <code>ILCursor</code> to search for a specific sequence of instructions with <code>GotoNext</code>: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); } </syntaxhighlight> This will tell the cursor to find an <code>ldarg.0</code> instruction, followed by a <code>ldfld</code> instruction with <code>jungleLeech</code> as the operand, et cetera. Crucially, it must find all seven of these instructions in order with no gaps. If successful, this will place the cursor at index 270. ===Step 4: Modify the instructions=== From earlier, we want to insert instructions to make the method skip checking whether <code>bodyChunk.owner is Player</code> and the following block. This just involves inserting an unconditional branch instruction. However, we have to tell it ''where'' to branch to, so we have one extra step of grabbing a reference to the instruction we want to branch to. Because we told the cursor to look for the entire sequence of 7 instructions, we can be sure they all exist here, and we don't have to use <code>GotoNext</code> to search again. We do the following to achieve this: Jump to the instruction that will skip the food drain code (276). <syntaxhighlight lang="csharp">c.Index += 6;</syntaxhighlight> Grab the operand of this instruction and store it locally. The operand of a branch instruction is always another <code>ILLabel</code> which points to the instruction of interest. <syntaxhighlight lang="csharp">ILLabel inst = (ILLabel)cursor.Next.Operand;</syntaxhighlight> Jump to just before the method is checking whether <code>bodyChunk.owner is Player</code> (273). <syntaxhighlight lang="csharp">c.Index -= 3;</syntaxhighlight> ''Emit'' an instruction to branch unconditionally to the instruction we referenced earlier, skipping the food drain block. <syntaxhighlight lang="csharp">cursor.Emit(OpCodes.Br, inst);</syntaxhighlight> This new instruction exists between instructions 272 and 273 because the cursor's <code>Index</code> at the time was 273. This is what our hooking method looks like now: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Br, inst); } </syntaxhighlight> What we've effectively done is changed this piece of <code>Leech.Attached</code>: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } </syntaxhighlight> into this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (false && bodyChunk.owner is Player && ...) { ... } </syntaxhighlight> We've now achieved exactly what we wanted but, for the sake of example, we will now attach this behavior to the value of a <code>Configurable<bool></code> (e.g., from a Remix <code>OptionInterface</code>) to illustrate how to reference things in the current context for the IL context. ===Step 5: Use a delegate to access the current context from the IL context=== We'll assume that you have already set up a <code>Configurable<bool></code> and an <code>OptionInterface</code> to allow toggling it, and that it is stored in the static field <code>Options.foodDrainToggle</code>. Although it would be possible to reference <code>Options.foodDrainToggle</code> with some specific sequence of instructions, we can give the <code>ILCursor</code> a ''delegate'' that we write in the current context instead, and it will store that delegate to use again in the IL context when the method is actually run. In this case, it would look like: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); </syntaxhighlight> The type argument indicates that the delegate takes no arguments (and thus removes nothing from the evaluation stack), but returns a boolean (which is then put on the stack). This needs to be placed just before the branch instruction we inserted earlier, which also needs to be changed to a conditional branch (<code>brfalse</code>) so that it actually checks the boolean we just put on the stack. Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> Note that when we emit, the cursor also moves forward, so we don't have to bump up the <code>Index</code> before inserting the next instruction. The equivalent C# code now looks like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } </syntaxhighlight> ===Step 6: Use a delegate to access the IL context from the current context=== We can put just about anything we want into the delegate. If we wanted to have Slugcat be [https://rainworld.miraheze.org/wiki/User:Alphappy/Live/Slowing slowed] while a Jungle Leech is attached, we could change our delegate to take in the <code>BodyChunk</code> that the original method already stored as a local: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); </syntaxhighlight> Note that this delegate ''does'' take one input, which we must put on the stack before calling this delegate. Fortunately, because it's a local we're using, that is very simple: <syntaxhighlight lang="csharp"> cursor.Emit(OpCodes.Ldloc, 0); </syntaxhighlight> Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Ldloc, 0); cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> The equivalent C# code now looks something like like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } </syntaxhighlight> Worth noting that, to achieve this slowing, we could have instead inserted a delegate after the instructions corresponding to <code>bodyChunk.owner is Player</code> instead so we don't have to make that check in our delegate. In that regard, what we've done here is inefficient, but it nonetheless demonstrates how to use something currently on the evaluation stack (that is, in the IL context) in the current context. ==Notes== ===Stack balance=== If you get an exception telling you that <code>ret</code> is an invalid OpCode, you've left the stack unbalanced. The number of objects on the stack before and after a method executes must be equal. If the stack is ''unbalanced'' - that is, more things are placed on the stack than are removed for a given method, or vice versa - the IL hook will fail. It is therefore important to understand [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields how each OpCode interacts with the stack]. Most instructions pop one object, push one object, or both - but some instructions may pop or push more than one object depending on their operand. ===Printing IL=== You can print the IL to the log: <code>Debug.Log(il.ToString());</code>. This will give you the same information that dnSpy's IL viewer does, although with slightly different syntax. Crucially, you can print the IL ''after'' your cursor has made all of its changes to make sure that they are the changes you intended. e09f6fc2654783cf603d95f3239eb9d648c0e7c4 554 553 2023-10-04T08:35:37Z Alphappy 121 slight change to C# code equivalents for consistency wikitext text/x-wiki '''IL hooking''', or '''intermediate-language hooking''', is an alternative to standard event hooking that allows for injection of arbitrary instructions within a method. ==Prerequisites== It is assumed that you fully understand how to use a standard event hook (<code>On</code>) as described at [[BepInPlugins]]. Additionally, it will be helpful to understand the concept of an [[w:Stack (abstract data type)|evaluation stack]], which is how objects are stored at the intermediate level. [[w:High-level programming language|High-level programming languages]] like C# abstract away the evaluation stack and allow for the more human-friendly use of named variables. This will be a little more complicated in IL. It is highly recommended to have a convenient way to view the IL instructions of Rain World's code. dnSpy can do this - right-click a line of code, and select ''Edit IL Instructions...'' We will cover how to interpret this information later. You will need to add several additional references to your project for IL hooking to work: *<code>Mono.Cecil.dll</code> *<code>Mono.Cecil.Mdb.dll</code> *<code>Mono.Cecil.Pdb.dll</code> *<code>Mono.Cecil.Rocks.dll</code> *<code>MonoMod.Common.dll</code> *<code>MonoMod.RuntimeDetour.dll</code> *<code>MonoMod.Utils.dll</code> These are normally in <code>Steam\steamapps\common\Rain World\RainWorld_Data\Managed</code> (although it is again recommended to copy them somewhere else first). This guide is intended to be self-sufficient, but see also [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ Risk of Thunder's guide to IL hooking] for another perspective and more examples. Everything in this guide is tested with Visual Studio 2022 17.7.0. ==Overview== Like standard event hooking, IL hooking targets a specific method in Rain World's assembly. There are a few key differences: *A standard event hook receives references to the original method <code>orig</code> and every argument that it would have received (including <code>this</code> if non-static, which the hook receives as <code>self</code> by default). An IL hook receives only an <code>ILContext</code> which is used to navigate the method's IL instructions. *The code you write in a standard event hook is run every time the game calls the hooked method (assuming no other mods hook that method and forgo the <code>orig</code> call). In an IL hook, the code you write is run only once when the mod is initialized, but the effect of this code is to essentially modify the original method directly. *A standard event hook can essentially only cause changes at the beginning or end of an existing method. An IL hook can cause changes inside a method. ==Procedure== As an example, we're going to hook <code>Leech.Attached</code> to prevent Jungle Leeches from draining Slugcat's food. As the relevant code is in the middle of the method, a standard event hook won't work (at least not easily). ===Step 1: Create an IL hook=== IL hooks are created similarly to standard event hooks. First, we must import a couple of things: <syntaxhighlight lang="csharp"> using Mono.Cecil.Cil; using MonoMod.Cil; </syntaxhighlight> Next, you can auto-generate the hooking method just as you would with a standard event hook. Pressing TAB twice after <code>+=</code> will create the hooking method automatically. <syntaxhighlight lang="csharp"> private void OnEnable() { IL.Leech.Attached += Leech_Attached; } private void Leech_Attached(ILContext il) { throw new NotImplementedException(); } </syntaxhighlight> You will also need to instantiate the cursor: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); } </syntaxhighlight> ===Step 2: Determine what to modify=== Before we can proceed, we need to know how to actually modify the method to get the effect we want. In <code>Leech.Attached</code>, the method checks whether the Leech in question is a Jungle Leech, then whether the creature it is attached to is a <code>Player</code> (Slugcat). Ultimately, we want the method to ''not'' check whether the creature is a <code>Player</code> and just skip the entire following block of code. Viewing the IL for this method reveals the following IL: <pre> 270 02FC ldarg.0 271 02FD ldfld bool Leech::jungleLeech 272 0302 brfalse 414 (050D) ldarg.0 273 0307 ldloc.0 274 0308 callvirt instance class PhysicalObject BodyChunk::get_owner() 275 030D isinst Player 276 0312 brfalse 340 (03F5) ldloc.0 </pre> Each row is an ''instruction''. The first column is the ''index'' of the instruction. The third column is the ''OpCode'' for that instruction, and the final column is the ''operand''. These instructions mean the following: {| class="wikitable" ! Index ! OpCode ! Operand ! Meaning |- | 270 | <code>ldarg.0</code> | | Put argument 0 on the evaluation stack. In a non-static class method, argument 0 is always a reference to <code>this</code>. |- | 271 | <code>ldfld</code> | <code>bool Leech::jungleLeech</code> | Pop an item off the stack, access its <code>jungleLeech</code> field, and put that <code>bool</code> on the stack. |- | 272 | <code>brfalse</code> | <code>414</code> | Pop an item off the stack. If it is false, go to the instruction at index 414. |- | 273 | <code>ldloc.0</code> | | Put local variable 0 on the stack (the first local variable defined in this method). This is the <code>BodyChunk</code> from a couple lines ago. |- | 274 | <code>callvirt</code> | <code>instance class PhysicalObject BodyChunk::get_owner()</code> | Pop an item off the stack, and call its <code>get_owner</code> property getter. Put the <code>PhysicalObject</code> instance that this returns on the stack. |- | 275 | <code>isinst</code> | <code>Player</code> | Pop an item off the stack. Put a <code>bool</code> on the stack corresponding to whether it is an instance of <code>Player</code>. |- | 276 | <code>brfalse</code> | <code>340</code> | Pop an item off the stack. If it is false, go to the instruction at index 340. |} Instructions 270 through 272 correspond to <code>if (this.JungleLeech)</code>, and instructions 273 through 275 correspond to <code>bodyChunk.owner is Player</code>. Because the conditional uses short-circuiting <code>&&</code> here, instruction 276 immediately skips if <code>bodyChunk.owner is Player</code> is <code>false</code>. We want to have the code not even bother with checking if it's a <code>Player</code> and skip the following block immediately, which we will do in the next sections. ===Step 3: Find the instructions of interest=== While we ''could'' tell the cursor to move directly to the index of the instructions we want to modify, that won't work reliably if any other mod IL hooks this method and changes the number of instructions. Instead, the better procedure is to ''search'' for a sequence of instructions. How many instructions should be included in this sequence is subjective. Too few, and there's a chance your hook will land somewhere it shouldn't; too many, and there's a chance another hook will modify code inside what you are trying to match, and your hook matches nothing and fails. In this example, matching instructions 270 through 276 should suffice. We tell our <code>ILCursor</code> to search for a specific sequence of instructions with <code>GotoNext</code>: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); } </syntaxhighlight> This will tell the cursor to find an <code>ldarg.0</code> instruction, followed by a <code>ldfld</code> instruction with <code>jungleLeech</code> as the operand, et cetera. Crucially, it must find all seven of these instructions in order with no gaps. If successful, this will place the cursor at index 270. ===Step 4: Modify the instructions=== From earlier, we want to insert instructions to make the method skip checking whether <code>bodyChunk.owner is Player</code> and the following block. This just involves inserting an unconditional branch instruction. However, we have to tell it ''where'' to branch to, so we have one extra step of grabbing a reference to the instruction we want to branch to. Because we told the cursor to look for the entire sequence of 7 instructions, we can be sure they all exist here, and we don't have to use <code>GotoNext</code> to search again. We do the following to achieve this: Jump to the instruction that will skip the food drain code (276). <syntaxhighlight lang="csharp">c.Index += 6;</syntaxhighlight> Grab the operand of this instruction and store it locally. The operand of a branch instruction is always another <code>ILLabel</code> which points to the instruction of interest. <syntaxhighlight lang="csharp">ILLabel inst = (ILLabel)cursor.Next.Operand;</syntaxhighlight> Jump to just before the method is checking whether <code>bodyChunk.owner is Player</code> (273). <syntaxhighlight lang="csharp">c.Index -= 3;</syntaxhighlight> ''Emit'' an instruction to branch unconditionally to the instruction we referenced earlier, skipping the food drain block. <syntaxhighlight lang="csharp">cursor.Emit(OpCodes.Br, inst);</syntaxhighlight> This new instruction exists between instructions 272 and 273 because the cursor's <code>Index</code> at the time was 273. This is what our hooking method looks like now: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Br, inst); } </syntaxhighlight> What we've effectively done is changed this piece of <code>Leech.Attached</code>: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> into this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (false && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> We've now achieved exactly what we wanted but, for the sake of example, we will now attach this behavior to the value of a <code>Configurable<bool></code> (e.g., from a Remix <code>OptionInterface</code>) to illustrate how to reference things in the current context for the IL context. ===Step 5: Use a delegate to access the current context from the IL context=== We'll assume that you have already set up a <code>Configurable<bool></code> and an <code>OptionInterface</code> to allow toggling it, and that it is stored in the static field <code>Options.foodDrainToggle</code>. Although it would be possible to reference <code>Options.foodDrainToggle</code> with some specific sequence of instructions, we can give the <code>ILCursor</code> a ''delegate'' that we write in the current context instead, and it will store that delegate to use again in the IL context when the method is actually run. In this case, it would look like: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); </syntaxhighlight> The type argument indicates that the delegate takes no arguments (and thus removes nothing from the evaluation stack), but returns a boolean (which is then put on the stack). This needs to be placed just before the branch instruction we inserted earlier, which also needs to be changed to a conditional branch (<code>brfalse</code>) so that it actually checks the boolean we just put on the stack. Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> Note that when we emit, the cursor also moves forward, so we don't have to bump up the <code>Index</code> before inserting the next instruction. The equivalent C# code now looks like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> ===Step 6: Use a delegate to access the IL context from the current context=== We can put just about anything we want into the delegate. If we wanted to have Slugcat be [https://rainworld.miraheze.org/wiki/User:Alphappy/Live/Slowing slowed] while a Jungle Leech is attached, we could change our delegate to take in the <code>BodyChunk</code> that the original method already stored as a local: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); </syntaxhighlight> Note that this delegate ''does'' take one input, which we must put on the stack before calling this delegate. Fortunately, because it's a local we're using, that is very simple: <syntaxhighlight lang="csharp"> cursor.Emit(OpCodes.Ldloc, 0); </syntaxhighlight> Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Ldloc, 0); cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> The equivalent C# code now looks something like like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> Worth noting that, to achieve this slowing, we could have instead inserted a delegate after the instructions corresponding to <code>bodyChunk.owner is Player</code> instead so we don't have to make that check in our delegate. In that regard, what we've done here is inefficient, but it nonetheless demonstrates how to use something currently on the evaluation stack (that is, in the IL context) in the current context. ==Notes== ===Stack balance=== If you get an exception telling you that <code>ret</code> is an invalid OpCode, you've left the stack unbalanced. The number of objects on the stack before and after a method executes must be equal. If the stack is ''unbalanced'' - that is, more things are placed on the stack than are removed for a given method, or vice versa - the IL hook will fail. It is therefore important to understand [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields how each OpCode interacts with the stack]. Most instructions pop one object, push one object, or both - but some instructions may pop or push more than one object depending on their operand. ===Printing IL=== You can print the IL to the log: <code>Debug.Log(il.ToString());</code>. This will give you the same information that dnSpy's IL viewer does, although with slightly different syntax. Crucially, you can print the IL ''after'' your cursor has made all of its changes to make sure that they are the changes you intended. 5fd0840885cda5b361212b849b0ae25e0a31e598 555 554 2023-10-04T20:45:14Z Alphappy 121 various clarifications; add stack column to table; a few grammatical corrections wikitext text/x-wiki '''IL hooking''', or '''intermediate-language hooking''', is an alternative to standard event hooking that allows for injection of arbitrary instructions within a method. ==Prerequisites== It is assumed that you fully understand how to use a standard event hook (<code>On</code>) as described at [[BepInPlugins]]. Additionally, it will be helpful to understand the concept of an [[w:Stack (abstract data type)|evaluation stack]], which is how objects are stored at the intermediate level. [[w:High-level programming language|High-level programming languages]] like C# abstract away the evaluation stack and allow for the more human-friendly use of named variables. This will be a little more complicated in IL - objects can only be ''pushed'' to the top of the stack or ''popped'' off the top of the stack; it is not possible to access anywhere else in the stack. It is highly recommended to have a convenient way to view the IL instructions of Rain World's code. dnSpy can do this - right-click a line of code, and select ''Edit IL Instructions...'' We will cover how to interpret this information later. You will need to add several additional references to your project for IL hooking to work: *<code>Mono.Cecil.dll</code> *<code>Mono.Cecil.Mdb.dll</code> *<code>Mono.Cecil.Pdb.dll</code> *<code>Mono.Cecil.Rocks.dll</code> *<code>MonoMod.Common.dll</code> *<code>MonoMod.RuntimeDetour.dll</code> *<code>MonoMod.Utils.dll</code> These are normally in <code>Steam\steamapps\common\Rain World\RainWorld_Data\Managed</code> (although it is again recommended to copy them somewhere else first). This guide is intended to be self-sufficient, but see also [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ Risk of Thunder's guide to IL hooking] for another perspective and more examples. A list of all IL instruction OpCodes and what they do can be found on [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields Microsoft's documentation page]. This is not required reading, but it will be a handy reference. Everything in this guide is tested with Visual Studio 2022 17.7.0, .NET Framework 4.0, and Rain World 1.9.07b. Newer versions could very well break something. ==Overview== Like standard event hooking, IL hooking targets a specific method in Rain World's assembly. There are a few key differences: *A standard event hook receives references to the original method <code>orig</code> and every argument that it would have received (including <code>this</code> if non-static, which the hook receives as <code>self</code> by default). An IL hook receives only an <code>ILContext</code> which is used to navigate the method's IL instructions. *The code you write in a standard event hook is run every time the game calls the hooked method (assuming no other mods hook that method and forgo the <code>orig</code> call). In an IL hook, the code you write is run only once when the mod is initialized, but the effect of this code is to essentially modify the original method directly. *A standard event hook can essentially only cause changes at the beginning or end of an existing method. An IL hook can cause changes inside a method. A mod with an IL hook is still a BepInPlugin. [[BepInPlugins#Testing your code|Building it]], creating a [[Downpour Reference/BepInEx Files|mod directory]], and [[Downpour Reference/Mod Directories|including other files]] is still the same process. ==Procedure== As an example, we're going to hook <code>Leech.Attached</code> to prevent Jungle Leeches from draining Slugcat's food. As the relevant code is in the middle of the method, a standard event hook won't work (at least not easily). ===Step 1: Create an IL hook=== IL hooks are created similarly to standard event hooks. First, we must import a couple of things (in addition to what you would import for standard event hooks): <syntaxhighlight lang="csharp"> using Mono.Cecil.Cil; using MonoMod.Cil; </syntaxhighlight> Next, you can auto-generate the hooking method just as you would with a standard event hook. Pressing TAB after <code>+=</code> will create the hooking method automatically. <syntaxhighlight lang="csharp"> private void OnEnable() { IL.Leech.Attached += Leech_Attached; } private void Leech_Attached(ILContext il) { throw new NotImplementedException(); } </syntaxhighlight> You will also need to instantiate the cursor: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); } </syntaxhighlight> ===Step 2: Determine what to modify=== Before we can proceed, we need to know how to actually modify the method to get the effect we want. In <code>Leech.Attached</code>, the method checks whether the Leech in question is a Jungle Leech, then whether the creature it is attached to is a <code>Player</code> (Slugcat): <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> Ultimately, we want the method to ''not'' check whether the creature is a <code>Player</code> and just skip the entire following block of code, while is responsible for the food drain. Viewing the IL for this method reveals the following: <pre> 270 02FC ldarg.0 271 02FD ldfld bool Leech::jungleLeech 272 0302 brfalse 414 (050D) ldarg.0 273 0307 ldloc.0 274 0308 callvirt instance class PhysicalObject BodyChunk::get_owner() 275 030D isinst Player 276 0312 brfalse 340 (03F5) ldloc.0 </pre> Each row is an ''instruction''. The first column is the ''index'' of the instruction, which will aid in discussion of where we want to make our modifications. The third column is the ''OpCode'' for that instruction, which is very generally what the instruction does. A list of all OpCodes and what they do can be found on [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields Microsoft's documentation page]. The final column is the ''operand'' for the instruction. These particular instructions mean the following: {| class="wikitable" ! Index ! OpCode ! Operand ! Meaning ! Top of stack |- | 270 | <code>ldarg.0</code> | | Put argument 0 on the evaluation stack. In a non-static class method, argument 0 is always a reference to <code>this</code>. | <code>Leech this</code> |- | 271 | <code>ldfld</code> | <code>bool Leech::jungleLeech</code> | Pop an item off the stack, access its <code>jungleLeech</code> field, and put that <code>bool</code> on the stack. | <code>bool this.jungleLeech</code> |- | 272 | <code>brfalse</code> | <code>414</code> | Pop an item off the stack. If it is false, go to the instruction at index 414. Index 414 is just after the entire <code>if (this.jungleLeech) { ... }</code> block. | irrelevant |- | 273 | <code>ldloc.0</code> | | Put local variable 0 on the stack (the first local variable defined in this method). | <code>BodyChunk bodyChunk</code> |- | 274 | <code>callvirt</code> | <code>instance class PhysicalObject BodyChunk::get_owner()</code> | Pop an item off the stack, and call its <code>get_owner</code> property getter, and put the result on the stack. | <code>PhysicalObject bodyChunk.owner</code> |- | 275 | <code>isinst</code> | <code>Player</code> | Pop an item off the stack. Put a <code>bool</code> on the stack corresponding to whether it is an instance of <code>Player</code>. | <code>bool (bodyChunk.owner is Player)</code> |- | 276 | <code>brfalse</code> | <code>340</code> | Pop an item off the stack. If it is false, go to the instruction at index 340. Index 340 is just after <code>if (bodyChunk.owner is Player & ...) { ... }</code>. | irrelevant |} Instructions 270 and 271 correspond to <code>if (this.JungleLeech)</code>, with 272 skipping the entire code block if it is false. Instructions 273 through 275 correspond to <code>if (bodyChunk.owner is Player)</code>, with 276 skipping just the code block that affects only Slugcat if it is false. While the second conditional here is compound, conditionals are broken into their individual parts and tested individually at the IL level. This is how [[w:Short-circuit evaluation|short-circuit evaluation]] is implemented: <code>(bodyChunk.owner is Player && somethingElse)</code> has no need to evaluate <code>somethingElse</code> if <code>bodyChunk.owner is Player</code> is false. We want to have the code not even bother with checking if <code>bodyChunk.owner is Player</code> and always skip the Slugcat-specific block (which is what instruction 276 does). ===Step 3: Find the instructions of interest=== While we ''could'' tell the cursor to move directly to the index of the instructions we want to modify, that won't work reliably if any other mod IL hooks this method and changes the number of instructions. Instead, the better procedure is to ''search'' for a sequence of instructions. How many instructions should be included in this sequence is subjective. Too few, and there's a chance your hook will land somewhere it shouldn't; too many, and there's a chance another hook will modify code inside what you are trying to match, and your hook matches nothing and fails. In this example, matching instructions 270 through 276 should suffice. We tell our <code>ILCursor</code> to search for a specific sequence of instructions with <code>GotoNext</code>: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); } </syntaxhighlight> This will tell the cursor to find an <code>ldarg.0</code> instruction, followed by a <code>ldfld</code> instruction with <code>jungleLeech</code> as the operand, et cetera. Crucially, it must find all seven of these instructions in order with no gaps. If successful, this will place the cursor at index 270 - the beginning of the instruction sequence we searched for. If it fails, an exception is thrown and this hook does not get applied. ===Step 4: Modify the instructions=== From earlier, we want to insert instructions to make the method skip checking whether <code>bodyChunk.owner is Player</code> and the following block. This just involves inserting an unconditional branch instruction. However, we have to tell it ''where'' to branch to, so we have one extra step of grabbing a reference to the instruction we want to branch to. Because we told the cursor to look for the entire sequence of 7 instructions, we can be sure they all exist here, and we don't have to use <code>GotoNext</code> to search again. We do the following to achieve this: Jump to the instruction that will skip the food drain code (276). <syntaxhighlight lang="csharp">c.Index += 6;</syntaxhighlight> Grab the operand of this instruction and store it locally. The operand of a branch instruction is always another <code>ILLabel</code> which points to the instruction of interest. <syntaxhighlight lang="csharp">ILLabel inst = (ILLabel)cursor.Next.Operand;</syntaxhighlight> Jump to just before the method is checking whether <code>bodyChunk.owner is Player</code> (273). <syntaxhighlight lang="csharp">c.Index -= 3;</syntaxhighlight> Insert, or ''emit'', an instruction to branch unconditionally to the instruction we referenced earlier, skipping the food drain block. <syntaxhighlight lang="csharp">cursor.Emit(OpCodes.Br, inst);</syntaxhighlight> This new instruction exists between instructions 272 and 273 because the cursor's <code>Index</code> at the time was 273. This is what our hooking method looks like now: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Br, inst); } </syntaxhighlight> What we've effectively done is changed this piece of <code>Leech.Attached</code>: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> into this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (false && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> We've now achieved exactly what we wanted but, for the sake of example, we will now attach this behavior to the value of a <code>Configurable<bool></code> (e.g., from a Remix <code>OptionInterface</code>) to illustrate how to reference things in the current context for the IL context. ===Step 5: Use a delegate to access the current context from the IL context=== We'll assume that you have already set up a <code>Configurable<bool></code> and an <code>OptionInterface</code> to allow toggling it, and that it is stored in the static field <code>Options.foodDrainToggle</code>. Although it would be possible to reference <code>Options.foodDrainToggle</code> with some specific sequence of instructions, we can give the <code>ILCursor</code> a ''delegate'' that we write in the current context instead, and it will store that delegate to use again in the IL context when the method is actually run. In this case, it would look like: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); </syntaxhighlight> The type argument <code>Func<bool></code> indicates that the delegate takes no arguments (and thus removes nothing from the evaluation stack), but returns a boolean (which is then put on the stack). This needs to be placed just before the branch instruction we inserted earlier, which also needs to be changed to a conditional branch (<code>brfalse</code>) so that it actually checks the boolean we just put on the stack. Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> Note that when we emit, the cursor also moves forward, so we don't have to bump up the <code>Index</code> before inserting the next instruction. It is worth emphasizing that if any instruction we insert (including delegates) puts something on the evaluation stack, there ''must'' be an instruction that removes it from the stack (which, in this case, <code>brfalse</code> does), lest we leave the stack [[#Stack balance|unbalanced]] and cause the hook to fail. The equivalent C# code now looks like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> ===Step 6: Use a delegate to access the IL context from the current context=== We can put just about anything we want into the delegate. If we wanted to have Slugcat be [https://rainworld.miraheze.org/wiki/User:Alphappy/Live/Slowing slowed] while a Jungle Leech is attached, we could change our delegate to take in the <code>BodyChunk</code> that the original method already stored as a local: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); </syntaxhighlight> In contrast to earlier, this delegate takes a <code>BodyChunk</code> as input, which we must put on the stack before calling this delegate. Fortunately, because this <code>BodyChunk</code> is stored as a local already where our instructions are being inserted, that is very simple: <syntaxhighlight lang="csharp"> cursor.Emit(OpCodes.Ldloc, 0); </syntaxhighlight> Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Ldloc, 0); cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> The equivalent C# code now looks something like like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> Worth noting that, to achieve this slowing, we could have instead inserted a delegate after the instructions corresponding to <code>bodyChunk.owner is Player</code> instead so we don't have to make that check in our delegate. In that regard, what we've done here is inefficient, but it nonetheless demonstrates how to use something currently on the evaluation stack (that is, in the IL context) in the current context. ==Notes== ===Stack balance=== If you get an exception telling you that <code>ret</code> is an invalid OpCode, you've left the stack unbalanced. The number of objects on the stack before and after a method executes must be equal. If the stack is ''unbalanced'' - that is, more things are placed on the stack than are removed for a given method, or vice versa - the IL hook will fail. It is therefore important to understand [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields how each OpCode interacts with the stack]. Most instructions pop one object, push one object, or both - but some instructions may pop or push more than one object depending on their operand. ===Printing IL=== You can print the IL to the log: <code>Debug.Log(il.ToString());</code>. This will give you the same information that dnSpy's IL viewer does, although with slightly different syntax. Crucially, you can print the IL ''after'' your cursor has made all of its changes to make sure that they are the changes you intended. ed64b3b4b82fc298fa4af5784fdb276be2c20725 556 555 2023-10-05T18:44:51Z Alphappy 121 /* Prerequisites */ correct .net version wikitext text/x-wiki '''IL hooking''', or '''intermediate-language hooking''', is an alternative to standard event hooking that allows for injection of arbitrary instructions within a method. ==Prerequisites== It is assumed that you fully understand how to use a standard event hook (<code>On</code>) as described at [[BepInPlugins]]. Additionally, it will be helpful to understand the concept of an [[w:Stack (abstract data type)|evaluation stack]], which is how objects are stored at the intermediate level. [[w:High-level programming language|High-level programming languages]] like C# abstract away the evaluation stack and allow for the more human-friendly use of named variables. This will be a little more complicated in IL - objects can only be ''pushed'' to the top of the stack or ''popped'' off the top of the stack; it is not possible to access anywhere else in the stack. It is highly recommended to have a convenient way to view the IL instructions of Rain World's code. dnSpy can do this - right-click a line of code, and select ''Edit IL Instructions...'' We will cover how to interpret this information later. You will need to add several additional references to your project for IL hooking to work: *<code>Mono.Cecil.dll</code> *<code>Mono.Cecil.Mdb.dll</code> *<code>Mono.Cecil.Pdb.dll</code> *<code>Mono.Cecil.Rocks.dll</code> *<code>MonoMod.Common.dll</code> *<code>MonoMod.RuntimeDetour.dll</code> *<code>MonoMod.Utils.dll</code> These are normally in <code>Steam\steamapps\common\Rain World\RainWorld_Data\Managed</code> (although it is again recommended to copy them somewhere else first). This guide is intended to be self-sufficient, but see also [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ Risk of Thunder's guide to IL hooking] for another perspective and more examples. A list of all IL instruction OpCodes and what they do can be found on [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields Microsoft's documentation page]. This is not required reading, but it will be a handy reference. Everything in this guide is tested with Visual Studio 2022 17.7.0, .NET Framework 4.8.04084, and Rain World 1.9.07b. Newer versions could very well break something. ==Overview== Like standard event hooking, IL hooking targets a specific method in Rain World's assembly. There are a few key differences: *A standard event hook receives references to the original method <code>orig</code> and every argument that it would have received (including <code>this</code> if non-static, which the hook receives as <code>self</code> by default). An IL hook receives only an <code>ILContext</code> which is used to navigate the method's IL instructions. *The code you write in a standard event hook is run every time the game calls the hooked method (assuming no other mods hook that method and forgo the <code>orig</code> call). In an IL hook, the code you write is run only once when the mod is initialized, but the effect of this code is to essentially modify the original method directly. *A standard event hook can essentially only cause changes at the beginning or end of an existing method. An IL hook can cause changes inside a method. A mod with an IL hook is still a BepInPlugin. [[BepInPlugins#Testing your code|Building it]], creating a [[Downpour Reference/BepInEx Files|mod directory]], and [[Downpour Reference/Mod Directories|including other files]] is still the same process. ==Procedure== As an example, we're going to hook <code>Leech.Attached</code> to prevent Jungle Leeches from draining Slugcat's food. As the relevant code is in the middle of the method, a standard event hook won't work (at least not easily). ===Step 1: Create an IL hook=== IL hooks are created similarly to standard event hooks. First, we must import a couple of things (in addition to what you would import for standard event hooks): <syntaxhighlight lang="csharp"> using Mono.Cecil.Cil; using MonoMod.Cil; </syntaxhighlight> Next, you can auto-generate the hooking method just as you would with a standard event hook. Pressing TAB after <code>+=</code> will create the hooking method automatically. <syntaxhighlight lang="csharp"> private void OnEnable() { IL.Leech.Attached += Leech_Attached; } private void Leech_Attached(ILContext il) { throw new NotImplementedException(); } </syntaxhighlight> You will also need to instantiate the cursor: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); } </syntaxhighlight> ===Step 2: Determine what to modify=== Before we can proceed, we need to know how to actually modify the method to get the effect we want. In <code>Leech.Attached</code>, the method checks whether the Leech in question is a Jungle Leech, then whether the creature it is attached to is a <code>Player</code> (Slugcat): <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> Ultimately, we want the method to ''not'' check whether the creature is a <code>Player</code> and just skip the entire following block of code, while is responsible for the food drain. Viewing the IL for this method reveals the following: <pre> 270 02FC ldarg.0 271 02FD ldfld bool Leech::jungleLeech 272 0302 brfalse 414 (050D) ldarg.0 273 0307 ldloc.0 274 0308 callvirt instance class PhysicalObject BodyChunk::get_owner() 275 030D isinst Player 276 0312 brfalse 340 (03F5) ldloc.0 </pre> Each row is an ''instruction''. The first column is the ''index'' of the instruction, which will aid in discussion of where we want to make our modifications. The third column is the ''OpCode'' for that instruction, which is very generally what the instruction does. A list of all OpCodes and what they do can be found on [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields Microsoft's documentation page]. The final column is the ''operand'' for the instruction. These particular instructions mean the following: {| class="wikitable" ! Index ! OpCode ! Operand ! Meaning ! Top of stack |- | 270 | <code>ldarg.0</code> | | Put argument 0 on the evaluation stack. In a non-static class method, argument 0 is always a reference to <code>this</code>. | <code>Leech this</code> |- | 271 | <code>ldfld</code> | <code>bool Leech::jungleLeech</code> | Pop an item off the stack, access its <code>jungleLeech</code> field, and put that <code>bool</code> on the stack. | <code>bool this.jungleLeech</code> |- | 272 | <code>brfalse</code> | <code>414</code> | Pop an item off the stack. If it is false, go to the instruction at index 414. Index 414 is just after the entire <code>if (this.jungleLeech) { ... }</code> block. | irrelevant |- | 273 | <code>ldloc.0</code> | | Put local variable 0 on the stack (the first local variable defined in this method). | <code>BodyChunk bodyChunk</code> |- | 274 | <code>callvirt</code> | <code>instance class PhysicalObject BodyChunk::get_owner()</code> | Pop an item off the stack, and call its <code>get_owner</code> property getter, and put the result on the stack. | <code>PhysicalObject bodyChunk.owner</code> |- | 275 | <code>isinst</code> | <code>Player</code> | Pop an item off the stack. Put a <code>bool</code> on the stack corresponding to whether it is an instance of <code>Player</code>. | <code>bool (bodyChunk.owner is Player)</code> |- | 276 | <code>brfalse</code> | <code>340</code> | Pop an item off the stack. If it is false, go to the instruction at index 340. Index 340 is just after <code>if (bodyChunk.owner is Player & ...) { ... }</code>. | irrelevant |} Instructions 270 and 271 correspond to <code>if (this.JungleLeech)</code>, with 272 skipping the entire code block if it is false. Instructions 273 through 275 correspond to <code>if (bodyChunk.owner is Player)</code>, with 276 skipping just the code block that affects only Slugcat if it is false. While the second conditional here is compound, conditionals are broken into their individual parts and tested individually at the IL level. This is how [[w:Short-circuit evaluation|short-circuit evaluation]] is implemented: <code>(bodyChunk.owner is Player && somethingElse)</code> has no need to evaluate <code>somethingElse</code> if <code>bodyChunk.owner is Player</code> is false. We want to have the code not even bother with checking if <code>bodyChunk.owner is Player</code> and always skip the Slugcat-specific block (which is what instruction 276 does). ===Step 3: Find the instructions of interest=== While we ''could'' tell the cursor to move directly to the index of the instructions we want to modify, that won't work reliably if any other mod IL hooks this method and changes the number of instructions. Instead, the better procedure is to ''search'' for a sequence of instructions. How many instructions should be included in this sequence is subjective. Too few, and there's a chance your hook will land somewhere it shouldn't; too many, and there's a chance another hook will modify code inside what you are trying to match, and your hook matches nothing and fails. In this example, matching instructions 270 through 276 should suffice. We tell our <code>ILCursor</code> to search for a specific sequence of instructions with <code>GotoNext</code>: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); } </syntaxhighlight> This will tell the cursor to find an <code>ldarg.0</code> instruction, followed by a <code>ldfld</code> instruction with <code>jungleLeech</code> as the operand, et cetera. Crucially, it must find all seven of these instructions in order with no gaps. If successful, this will place the cursor at index 270 - the beginning of the instruction sequence we searched for. If it fails, an exception is thrown and this hook does not get applied. ===Step 4: Modify the instructions=== From earlier, we want to insert instructions to make the method skip checking whether <code>bodyChunk.owner is Player</code> and the following block. This just involves inserting an unconditional branch instruction. However, we have to tell it ''where'' to branch to, so we have one extra step of grabbing a reference to the instruction we want to branch to. Because we told the cursor to look for the entire sequence of 7 instructions, we can be sure they all exist here, and we don't have to use <code>GotoNext</code> to search again. We do the following to achieve this: Jump to the instruction that will skip the food drain code (276). <syntaxhighlight lang="csharp">c.Index += 6;</syntaxhighlight> Grab the operand of this instruction and store it locally. The operand of a branch instruction is always another <code>ILLabel</code> which points to the instruction of interest. <syntaxhighlight lang="csharp">ILLabel inst = (ILLabel)cursor.Next.Operand;</syntaxhighlight> Jump to just before the method is checking whether <code>bodyChunk.owner is Player</code> (273). <syntaxhighlight lang="csharp">c.Index -= 3;</syntaxhighlight> Insert, or ''emit'', an instruction to branch unconditionally to the instruction we referenced earlier, skipping the food drain block. <syntaxhighlight lang="csharp">cursor.Emit(OpCodes.Br, inst);</syntaxhighlight> This new instruction exists between instructions 272 and 273 because the cursor's <code>Index</code> at the time was 273. This is what our hooking method looks like now: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Br, inst); } </syntaxhighlight> What we've effectively done is changed this piece of <code>Leech.Attached</code>: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> into this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (false && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> We've now achieved exactly what we wanted but, for the sake of example, we will now attach this behavior to the value of a <code>Configurable<bool></code> (e.g., from a Remix <code>OptionInterface</code>) to illustrate how to reference things in the current context for the IL context. ===Step 5: Use a delegate to access the current context from the IL context=== We'll assume that you have already set up a <code>Configurable<bool></code> and an <code>OptionInterface</code> to allow toggling it, and that it is stored in the static field <code>Options.foodDrainToggle</code>. Although it would be possible to reference <code>Options.foodDrainToggle</code> with some specific sequence of instructions, we can give the <code>ILCursor</code> a ''delegate'' that we write in the current context instead, and it will store that delegate to use again in the IL context when the method is actually run. In this case, it would look like: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); </syntaxhighlight> The type argument <code>Func<bool></code> indicates that the delegate takes no arguments (and thus removes nothing from the evaluation stack), but returns a boolean (which is then put on the stack). This needs to be placed just before the branch instruction we inserted earlier, which also needs to be changed to a conditional branch (<code>brfalse</code>) so that it actually checks the boolean we just put on the stack. Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> Note that when we emit, the cursor also moves forward, so we don't have to bump up the <code>Index</code> before inserting the next instruction. It is worth emphasizing that if any instruction we insert (including delegates) puts something on the evaluation stack, there ''must'' be an instruction that removes it from the stack (which, in this case, <code>brfalse</code> does), lest we leave the stack [[#Stack balance|unbalanced]] and cause the hook to fail. The equivalent C# code now looks like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> ===Step 6: Use a delegate to access the IL context from the current context=== We can put just about anything we want into the delegate. If we wanted to have Slugcat be [https://rainworld.miraheze.org/wiki/User:Alphappy/Live/Slowing slowed] while a Jungle Leech is attached, we could change our delegate to take in the <code>BodyChunk</code> that the original method already stored as a local: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); </syntaxhighlight> In contrast to earlier, this delegate takes a <code>BodyChunk</code> as input, which we must put on the stack before calling this delegate. Fortunately, because this <code>BodyChunk</code> is stored as a local already where our instructions are being inserted, that is very simple: <syntaxhighlight lang="csharp"> cursor.Emit(OpCodes.Ldloc, 0); </syntaxhighlight> Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Ldloc, 0); cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> The equivalent C# code now looks something like like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> Worth noting that, to achieve this slowing, we could have instead inserted a delegate after the instructions corresponding to <code>bodyChunk.owner is Player</code> instead so we don't have to make that check in our delegate. In that regard, what we've done here is inefficient, but it nonetheless demonstrates how to use something currently on the evaluation stack (that is, in the IL context) in the current context. ==Notes== ===Stack balance=== If you get an exception telling you that <code>ret</code> is an invalid OpCode, you've left the stack unbalanced. The number of objects on the stack before and after a method executes must be equal. If the stack is ''unbalanced'' - that is, more things are placed on the stack than are removed for a given method, or vice versa - the IL hook will fail. It is therefore important to understand [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields how each OpCode interacts with the stack]. Most instructions pop one object, push one object, or both - but some instructions may pop or push more than one object depending on their operand. ===Printing IL=== You can print the IL to the log: <code>Debug.Log(il.ToString());</code>. This will give you the same information that dnSpy's IL viewer does, although with slightly different syntax. Crucially, you can print the IL ''after'' your cursor has made all of its changes to make sure that they are the changes you intended. c3d464adc1cf1a8b9f76bdbcf7f8d61fb94db593 557 556 2023-10-08T00:15:39Z Alphappy 121 expand on viewing the modified IL wikitext text/x-wiki '''IL hooking''', or '''intermediate-language hooking''', is an alternative to standard event hooking that allows for injection of arbitrary instructions within a method. ==Prerequisites== It is assumed that you fully understand how to use a standard event hook (<code>On</code>) as described at [[BepInPlugins]]. Additionally, it will be helpful to understand the concept of an [[w:Stack (abstract data type)|evaluation stack]], which is how objects are stored at the intermediate level. [[w:High-level programming language|High-level programming languages]] like C# abstract away the evaluation stack and allow for the more human-friendly use of named variables. This will be a little more complicated in IL - objects can only be ''pushed'' to the top of the stack or ''popped'' off the top of the stack; it is not possible to access anywhere else in the stack. It is highly recommended to have a convenient way to view the IL instructions of Rain World's code. dnSpy can do this - right-click a line of code, and select ''Edit IL Instructions...'' We will cover how to interpret this information later. You will need to add several additional references to your project for IL hooking to work: *<code>Mono.Cecil.dll</code> *<code>Mono.Cecil.Mdb.dll</code> *<code>Mono.Cecil.Pdb.dll</code> *<code>Mono.Cecil.Rocks.dll</code> *<code>MonoMod.Common.dll</code> *<code>MonoMod.RuntimeDetour.dll</code> *<code>MonoMod.Utils.dll</code> These are normally in <code>Steam\steamapps\common\Rain World\RainWorld_Data\Managed</code> (although it is again recommended to copy them somewhere else first). This guide is intended to be self-sufficient, but see also [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ Risk of Thunder's guide to IL hooking] for another perspective and more examples. A list of all IL instruction OpCodes and what they do can be found on [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields Microsoft's documentation page]. This is not required reading, but it will be a handy reference. Everything in this guide is tested with Visual Studio 2022 17.7.0, .NET Framework 4.8.04084, and Rain World 1.9.07b. Newer versions could very well break something. ==Overview== Like standard event hooking, IL hooking targets a specific method in Rain World's assembly. There are a few key differences: *A standard event hook receives references to the original method <code>orig</code> and every argument that it would have received (including <code>this</code> if non-static, which the hook receives as <code>self</code> by default). An IL hook receives only an <code>ILContext</code> which is used to navigate the method's IL instructions. *The code you write in a standard event hook is run every time the game calls the hooked method (assuming no other mods hook that method and forgo the <code>orig</code> call). In an IL hook, the code you write is run only once when the mod is initialized, but the effect of this code is to essentially modify the original method directly. *A standard event hook can essentially only cause changes at the beginning or end of an existing method. An IL hook can cause changes inside a method. A mod with an IL hook is still a BepInPlugin. [[BepInPlugins#Testing your code|Building it]], creating a [[Downpour Reference/BepInEx Files|mod directory]], and [[Downpour Reference/Mod Directories|including other files]] is still the same process. ==Procedure== As an example, we're going to hook <code>Leech.Attached</code> to prevent Jungle Leeches from draining Slugcat's food. As the relevant code is in the middle of the method, a standard event hook won't work (at least not easily). ===Step 1: Create an IL hook=== IL hooks are created similarly to standard event hooks. First, we must import a couple of things (in addition to what you would import for standard event hooks): <syntaxhighlight lang="csharp"> using Mono.Cecil.Cil; using MonoMod.Cil; </syntaxhighlight> Next, you can auto-generate the hooking method just as you would with a standard event hook. Pressing TAB after <code>+=</code> will create the hooking method automatically. <syntaxhighlight lang="csharp"> private void OnEnable() { IL.Leech.Attached += Leech_Attached; } private void Leech_Attached(ILContext il) { throw new NotImplementedException(); } </syntaxhighlight> You will also need to instantiate the cursor: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); } </syntaxhighlight> ===Step 2: Determine what to modify=== Before we can proceed, we need to know how to actually modify the method to get the effect we want. In <code>Leech.Attached</code>, the method checks whether the Leech in question is a Jungle Leech, then whether the creature it is attached to is a <code>Player</code> (Slugcat): <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> Ultimately, we want the method to ''not'' check whether the creature is a <code>Player</code> and just skip the entire following block of code, while is responsible for the food drain. Viewing the IL for this method reveals the following: <pre> 270 02FC ldarg.0 271 02FD ldfld bool Leech::jungleLeech 272 0302 brfalse 414 (050D) ldarg.0 273 0307 ldloc.0 274 0308 callvirt instance class PhysicalObject BodyChunk::get_owner() 275 030D isinst Player 276 0312 brfalse 340 (03F5) ldloc.0 </pre> Each row is an ''instruction''. The first column is the ''index'' of the instruction, which will aid in discussion of where we want to make our modifications. The third column is the ''OpCode'' for that instruction, which is very generally what the instruction does. A list of all OpCodes and what they do can be found on [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields Microsoft's documentation page]. The final column is the ''operand'' for the instruction. These particular instructions mean the following: {| class="wikitable" ! Index ! OpCode ! Operand ! Meaning ! Top of stack |- | 270 | <code>ldarg.0</code> | | Put argument 0 on the evaluation stack. In a non-static class method, argument 0 is always a reference to <code>this</code>. | <code>Leech this</code> |- | 271 | <code>ldfld</code> | <code>bool Leech::jungleLeech</code> | Pop an item off the stack, access its <code>jungleLeech</code> field, and put that <code>bool</code> on the stack. | <code>bool this.jungleLeech</code> |- | 272 | <code>brfalse</code> | <code>414</code> | Pop an item off the stack. If it is false, go to the instruction at index 414. Index 414 is just after the entire <code>if (this.jungleLeech) { ... }</code> block. | irrelevant |- | 273 | <code>ldloc.0</code> | | Put local variable 0 on the stack (the first local variable defined in this method). | <code>BodyChunk bodyChunk</code> |- | 274 | <code>callvirt</code> | <code>instance class PhysicalObject BodyChunk::get_owner()</code> | Pop an item off the stack, and call its <code>get_owner</code> property getter, and put the result on the stack. | <code>PhysicalObject bodyChunk.owner</code> |- | 275 | <code>isinst</code> | <code>Player</code> | Pop an item off the stack. Put a <code>bool</code> on the stack corresponding to whether it is an instance of <code>Player</code>. | <code>bool (bodyChunk.owner is Player)</code> |- | 276 | <code>brfalse</code> | <code>340</code> | Pop an item off the stack. If it is false, go to the instruction at index 340. Index 340 is just after <code>if (bodyChunk.owner is Player & ...) { ... }</code>. | irrelevant |} Instructions 270 and 271 correspond to <code>if (this.JungleLeech)</code>, with 272 skipping the entire code block if it is false. Instructions 273 through 275 correspond to <code>if (bodyChunk.owner is Player)</code>, with 276 skipping just the code block that affects only Slugcat if it is false. While the second conditional here is compound, conditionals are broken into their individual parts and tested individually at the IL level. This is how [[w:Short-circuit evaluation|short-circuit evaluation]] is implemented: <code>(bodyChunk.owner is Player && somethingElse)</code> has no need to evaluate <code>somethingElse</code> if <code>bodyChunk.owner is Player</code> is false. We want to have the code not even bother with checking if <code>bodyChunk.owner is Player</code> and always skip the Slugcat-specific block (which is what instruction 276 does). ===Step 3: Find the instructions of interest=== While we ''could'' tell the cursor to move directly to the index of the instructions we want to modify, that won't work reliably if any other mod IL hooks this method and changes the number of instructions. Instead, the better procedure is to ''search'' for a sequence of instructions. How many instructions should be included in this sequence is subjective. Too few, and there's a chance your hook will land somewhere it shouldn't; too many, and there's a chance another hook will modify code inside what you are trying to match, and your hook matches nothing and fails. In this example, matching instructions 270 through 276 should suffice. We tell our <code>ILCursor</code> to search for a specific sequence of instructions with <code>GotoNext</code>: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); } </syntaxhighlight> This will tell the cursor to find an <code>ldarg.0</code> instruction, followed by a <code>ldfld</code> instruction with <code>jungleLeech</code> as the operand, et cetera. Crucially, it must find all seven of these instructions in order with no gaps. If successful, this will place the cursor at index 270 - the beginning of the instruction sequence we searched for. If it fails, an exception is thrown and this hook does not get applied. ===Step 4: Modify the instructions=== From earlier, we want to insert instructions to make the method skip checking whether <code>bodyChunk.owner is Player</code> and the following block. This just involves inserting an unconditional branch instruction. However, we have to tell it ''where'' to branch to, so we have one extra step of grabbing a reference to the instruction we want to branch to. Because we told the cursor to look for the entire sequence of 7 instructions, we can be sure they all exist here, and we don't have to use <code>GotoNext</code> to search again. We do the following to achieve this: Jump to the instruction that will skip the food drain code (276). <syntaxhighlight lang="csharp">c.Index += 6;</syntaxhighlight> Grab the operand of this instruction and store it locally. The operand of a branch instruction is always another <code>ILLabel</code> which points to the instruction of interest. <syntaxhighlight lang="csharp">ILLabel inst = (ILLabel)cursor.Next.Operand;</syntaxhighlight> Jump to just before the method is checking whether <code>bodyChunk.owner is Player</code> (273). <syntaxhighlight lang="csharp">c.Index -= 3;</syntaxhighlight> Insert, or ''emit'', an instruction to branch unconditionally to the instruction we referenced earlier, skipping the food drain block. <syntaxhighlight lang="csharp">cursor.Emit(OpCodes.Br, inst);</syntaxhighlight> This new instruction exists between instructions 272 and 273 because the cursor's <code>Index</code> at the time was 273. This is what our hooking method looks like now: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Br, inst); } </syntaxhighlight> What we've effectively done is changed this piece of <code>Leech.Attached</code>: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> into this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (false && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> We've now achieved exactly what we wanted but, for the sake of example, we will now attach this behavior to the value of a <code>Configurable<bool></code> (e.g., from a Remix <code>OptionInterface</code>) to illustrate how to reference things in the current context for the IL context. ===Step 5: Use a delegate to access the current context from the IL context=== We'll assume that you have already set up a <code>Configurable<bool></code> and an <code>OptionInterface</code> to allow toggling it, and that it is stored in the static field <code>Options.foodDrainToggle</code>. Although it would be possible to reference <code>Options.foodDrainToggle</code> with some specific sequence of instructions, we can give the <code>ILCursor</code> a ''delegate'' that we write in the current context instead, and it will store that delegate to use again in the IL context when the method is actually run. In this case, it would look like: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); </syntaxhighlight> The type argument <code>Func<bool></code> indicates that the delegate takes no arguments (and thus removes nothing from the evaluation stack), but returns a boolean (which is then put on the stack). This needs to be placed just before the branch instruction we inserted earlier, which also needs to be changed to a conditional branch (<code>brfalse</code>) so that it actually checks the boolean we just put on the stack. Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> Note that when we emit, the cursor also moves forward, so we don't have to bump up the <code>Index</code> before inserting the next instruction. It is worth emphasizing that if any instruction we insert (including delegates) puts something on the evaluation stack, there ''must'' be an instruction that removes it from the stack (which, in this case, <code>brfalse</code> does), lest we leave the stack [[#Stack balance|unbalanced]] and cause the hook to fail. The equivalent C# code now looks like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> ===Step 6: Use a delegate to access the IL context from the current context=== We can put just about anything we want into the delegate. If we wanted to have Slugcat be [https://rainworld.miraheze.org/wiki/User:Alphappy/Live/Slowing slowed] while a Jungle Leech is attached, we could change our delegate to take in the <code>BodyChunk</code> that the original method already stored as a local: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); </syntaxhighlight> In contrast to earlier, this delegate takes a <code>BodyChunk</code> as input, which we must put on the stack before calling this delegate. Fortunately, because this <code>BodyChunk</code> is stored as a local already where our instructions are being inserted, that is very simple: <syntaxhighlight lang="csharp"> cursor.Emit(OpCodes.Ldloc, 0); </syntaxhighlight> Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Ldloc, 0); cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> The equivalent C# code now looks something like like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> Worth noting that, to achieve this slowing, we could have instead inserted a delegate after the instructions corresponding to <code>bodyChunk.owner is Player</code> instead so we don't have to make that check in our delegate. In that regard, what we've done here is inefficient, but it nonetheless demonstrates how to use something currently on the evaluation stack (that is, in the IL context) in the current context. ===Step 7: View the modified IL for debugging=== If you add <code>Debug.Log(il.ToString());</code> to the end of your hook, it will print the modified method. You will notice that this puts hundreds of lines in the log - thousands for longer methods. As such, it is best to not print this unless you are debugging. Assuming you did all of the above, you should see the following in the middle of the printout: <pre> IL_02fc: ldarg.0 IL_02fd: ldfld System.Boolean Leech::jungleLeech IL_0302: brfalse IL_050d IL_0000: ldloc V_0 IL_0000: ldc.i4 0 IL_0000: call T MonoMod.Cil.RuntimeILReferenceBag/InnerBag`1<System.Func`2<BodyChunk,System.Boolean>>::Get(System.Int32) IL_0000: call TResult MonoMod.Cil.RuntimeILReferenceBag/FastDelegateInvokers::Invoke<BodyChunk,System.Boolean>(T1,MonoMod.Cil.RuntimeILReferenceBag/FastDelegateInvokers/Func`2<T1,TResult>) IL_0000: brfalse IL_03f5 IL_0307: ldloc.0 IL_0308: callvirt PhysicalObject BodyChunk::get_owner() IL_030d: isinst Player IL_0312: brfalse IL_03f5 </pre> This shows ''offsets'' and not indices as dnSpy did. They are not sequential and not unique for our added IL, but they still allow us to make sure our hook is doing what we intended - for instance, we can see the <code>ldloc</code> and the <code>brfalse</code> we explicitly added with <code>Emit</code>. We also see three instructions that MonoMod added to call our delegate. They look messy because of how type arguments must be passed around, but all they do is *put an identifier for our delegate on the stack; *call a method to retrieve the delegate; and *call a method to invoke the delegate. For completeness, here's what these five new instructions mean: {| class="wikitable" ! OpCode ! Operand ! Meaning ! Top of stack |- | <code>ldloc</code> | <code>V_0</code> | Put local variable 0 on the stack (the first local variable defined in this method). | <code>BodyChunk bodyChunk</code> |- | <code>ldc.i4</code> | <code>0</code> | Put the integer 0 on the stack. | <code>int 0</code><br><code>BodyChunk bodyChunk</code> |- | <code>call</code> | <code>T ...RuntimeILReferenceBag/InnerBag...</code> | Call MonoMod's <code>InnerBag</code>. Because this takes one input, this also pops one item off the stack. When our hooking method ran, MonoMod gave our delegate an identifier of <code>0</code>.<br> <code>InnerBag</code>, when given that identifier, will return our delegate.<br> Put the resulting <code>Func<BodyChunk, bool></code>, which is our delegate, on the stack. | <code>Func<BodyChunk, bool> delegate</code><br><code>BodyChunk bodyChunk</code> |- | <code>call</code> | <code>TResult ...FastDelegateInvokers::Invoke...</code> | Call MonoMod's <code>Invoke</code>. This will pop a number of items off the stack equal to the number of arguments to the delegate plus one.<br> In our case, it will take two arguments, which are expected to be the delegate and a <code>BodyChunk</code>.<br> MonoMod will then ''invoke'' our delegate, passing the <code>BodyChunk</code> as the sole argument.<br> Put the resulting <code>bool</code> (the <code>TResult</code> of our delegate) on the stack. | <code>bool delegate(BodyChunk bodyChunk)</code> |- | <code>brfalse</code> | <code>IL_03f5</code> | Pop an item off the stack. If it is false, go to the instruction at offset 03f5. Offset 03f5 is just after <code>if (bodyChunk.owner is Player & ...) { ... }</code>. | irrelevant |} Note that the five instructions we've added collectively push to and pop from the stack the same number of times (four, in this case). This is necessary for [[#Stack balance|stack balance]]. ==Notes== ===Stack balance=== If you get an exception telling you that <code>ret</code> is an invalid OpCode, you've left the stack unbalanced. The number of objects on the stack before and after a method executes must be equal. If the stack is ''unbalanced'' - that is, more things are placed on the stack than are removed for a given method, or vice versa - the IL hook will fail. It is therefore important to understand [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields how each OpCode interacts with the stack]. Most instructions pop one object, push one object, or both - but some instructions may pop or push more than one object depending on their operand. afc5185144859cf0d24ccb3d128ad23000842107 558 557 2023-10-08T00:22:09Z Alphappy 121 correction to monomod delegate instructions (and consistency) wikitext text/x-wiki '''IL hooking''', or '''intermediate-language hooking''', is an alternative to standard event hooking that allows for injection of arbitrary instructions within a method. ==Prerequisites== It is assumed that you fully understand how to use a standard event hook (<code>On</code>) as described at [[BepInPlugins]]. Additionally, it will be helpful to understand the concept of an [[w:Stack (abstract data type)|evaluation stack]], which is how objects are stored at the intermediate level. [[w:High-level programming language|High-level programming languages]] like C# abstract away the evaluation stack and allow for the more human-friendly use of named variables. This will be a little more complicated in IL - objects can only be ''pushed'' to the top of the stack or ''popped'' off the top of the stack; it is not possible to access anywhere else in the stack. It is highly recommended to have a convenient way to view the IL instructions of Rain World's code. dnSpy can do this - right-click a line of code, and select ''Edit IL Instructions...'' We will cover how to interpret this information later. You will need to add several additional references to your project for IL hooking to work: *<code>Mono.Cecil.dll</code> *<code>Mono.Cecil.Mdb.dll</code> *<code>Mono.Cecil.Pdb.dll</code> *<code>Mono.Cecil.Rocks.dll</code> *<code>MonoMod.Common.dll</code> *<code>MonoMod.RuntimeDetour.dll</code> *<code>MonoMod.Utils.dll</code> These are normally in <code>Steam\steamapps\common\Rain World\RainWorld_Data\Managed</code> (although it is again recommended to copy them somewhere else first). This guide is intended to be self-sufficient, but see also [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ Risk of Thunder's guide to IL hooking] for another perspective and more examples. A list of all IL instruction OpCodes and what they do can be found on [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields Microsoft's documentation page]. This is not required reading, but it will be a handy reference. Everything in this guide is tested with Visual Studio 2022 17.7.0, .NET Framework 4.8.04084, and Rain World 1.9.07b. Newer versions could very well break something. ==Overview== Like standard event hooking, IL hooking targets a specific method in Rain World's assembly. There are a few key differences: *A standard event hook receives references to the original method <code>orig</code> and every argument that it would have received (including <code>this</code> if non-static, which the hook receives as <code>self</code> by default). An IL hook receives only an <code>ILContext</code> which is used to navigate the method's IL instructions. *The code you write in a standard event hook is run every time the game calls the hooked method (assuming no other mods hook that method and forgo the <code>orig</code> call). In an IL hook, the code you write is run only once when the mod is initialized, but the effect of this code is to essentially modify the original method directly. *A standard event hook can essentially only cause changes at the beginning or end of an existing method. An IL hook can cause changes inside a method. A mod with an IL hook is still a BepInPlugin. [[BepInPlugins#Testing your code|Building it]], creating a [[Downpour Reference/BepInEx Files|mod directory]], and [[Downpour Reference/Mod Directories|including other files]] is still the same process. ==Procedure== As an example, we're going to hook <code>Leech.Attached</code> to prevent Jungle Leeches from draining Slugcat's food. As the relevant code is in the middle of the method, a standard event hook won't work (at least not easily). ===Step 1: Create an IL hook=== IL hooks are created similarly to standard event hooks. First, we must import a couple of things (in addition to what you would import for standard event hooks): <syntaxhighlight lang="csharp"> using Mono.Cecil.Cil; using MonoMod.Cil; </syntaxhighlight> Next, you can auto-generate the hooking method just as you would with a standard event hook. Pressing TAB after <code>+=</code> will create the hooking method automatically. <syntaxhighlight lang="csharp"> private void OnEnable() { IL.Leech.Attached += Leech_Attached; } private void Leech_Attached(ILContext il) { throw new NotImplementedException(); } </syntaxhighlight> You will also need to instantiate the cursor: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); } </syntaxhighlight> ===Step 2: Determine what to modify=== Before we can proceed, we need to know how to actually modify the method to get the effect we want. In <code>Leech.Attached</code>, the method checks whether the Leech in question is a Jungle Leech, then whether the creature it is attached to is a <code>Player</code> (Slugcat): <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> Ultimately, we want the method to ''not'' check whether the creature is a <code>Player</code> and just skip the entire following block of code, while is responsible for the food drain. Viewing the IL for this method reveals the following: <pre> 270 02FC ldarg.0 271 02FD ldfld bool Leech::jungleLeech 272 0302 brfalse 414 (050D) ldarg.0 273 0307 ldloc.0 274 0308 callvirt instance class PhysicalObject BodyChunk::get_owner() 275 030D isinst Player 276 0312 brfalse 340 (03F5) ldloc.0 </pre> Each row is an ''instruction''. The first column is the ''index'' of the instruction, which will aid in discussion of where we want to make our modifications. The third column is the ''OpCode'' for that instruction, which is very generally what the instruction does. A list of all OpCodes and what they do can be found on [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields Microsoft's documentation page]. The final column is the ''operand'' for the instruction. These particular instructions mean the following: {| class="wikitable" ! Index ! OpCode ! Operand ! Meaning ! Top of stack |- | 270 | <code>ldarg.0</code> | | Put argument 0 on the evaluation stack. In a non-static class method, argument 0 is always a reference to <code>this</code>. | <code>Leech this</code> |- | 271 | <code>ldfld</code> | <code>bool Leech::jungleLeech</code> | Pop an item off the stack, access its <code>jungleLeech</code> field, and put that <code>bool</code> on the stack. | <code>bool this.jungleLeech</code> |- | 272 | <code>brfalse</code> | <code>414</code> | Pop an item off the stack. If it is false, go to the instruction at index 414. Index 414 is just after the entire <code>if (this.jungleLeech) { ... }</code> block. | irrelevant |- | 273 | <code>ldloc.0</code> | | Put local variable 0 on the stack (the first local variable defined in this method). | <code>BodyChunk bodyChunk</code> |- | 274 | <code>callvirt</code> | <code>instance class PhysicalObject BodyChunk::get_owner()</code> | Pop an item off the stack, and call its <code>get_owner</code> property getter, and put the result on the stack. | <code>PhysicalObject bodyChunk.owner</code> |- | 275 | <code>isinst</code> | <code>Player</code> | Pop an item off the stack. Put a <code>bool</code> on the stack corresponding to whether it is an instance of <code>Player</code>. | <code>bool (bodyChunk.owner is Player)</code> |- | 276 | <code>brfalse</code> | <code>340</code> | Pop an item off the stack. If it is false, go to the instruction at index 340. Index 340 is just after <code>if (bodyChunk.owner is Player & ...) { ... }</code>. | irrelevant |} Instructions 270 and 271 correspond to <code>if (this.JungleLeech)</code>, with 272 skipping the entire code block if it is false. Instructions 273 through 275 correspond to <code>if (bodyChunk.owner is Player)</code>, with 276 skipping just the code block that affects only Slugcat if it is false. While the second conditional here is compound, conditionals are broken into their individual parts and tested individually at the IL level. This is how [[w:Short-circuit evaluation|short-circuit evaluation]] is implemented: <code>(bodyChunk.owner is Player && somethingElse)</code> has no need to evaluate <code>somethingElse</code> if <code>bodyChunk.owner is Player</code> is false. We want to have the code not even bother with checking if <code>bodyChunk.owner is Player</code> and always skip the Slugcat-specific block (which is what instruction 276 does). ===Step 3: Find the instructions of interest=== While we ''could'' tell the cursor to move directly to the index of the instructions we want to modify, that won't work reliably if any other mod IL hooks this method and changes the number of instructions. Instead, the better procedure is to ''search'' for a sequence of instructions. How many instructions should be included in this sequence is subjective. Too few, and there's a chance your hook will land somewhere it shouldn't; too many, and there's a chance another hook will modify code inside what you are trying to match, and your hook matches nothing and fails. In this example, matching instructions 270 through 276 should suffice. We tell our <code>ILCursor</code> to search for a specific sequence of instructions with <code>GotoNext</code>: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); } </syntaxhighlight> This will tell the cursor to find an <code>ldarg.0</code> instruction, followed by a <code>ldfld</code> instruction with <code>jungleLeech</code> as the operand, et cetera. Crucially, it must find all seven of these instructions in order with no gaps. If successful, this will place the cursor at index 270 - the beginning of the instruction sequence we searched for. If it fails, an exception is thrown and this hook does not get applied. ===Step 4: Modify the instructions=== From earlier, we want to insert instructions to make the method skip checking whether <code>bodyChunk.owner is Player</code> and the following block. This just involves inserting an unconditional branch instruction. However, we have to tell it ''where'' to branch to, so we have one extra step of grabbing a reference to the instruction we want to branch to. Because we told the cursor to look for the entire sequence of 7 instructions, we can be sure they all exist here, and we don't have to use <code>GotoNext</code> to search again. We do the following to achieve this: Jump to the instruction that will skip the food drain code (276). <syntaxhighlight lang="csharp">c.Index += 6;</syntaxhighlight> Grab the operand of this instruction and store it locally. The operand of a branch instruction is always another <code>ILLabel</code> which points to the instruction of interest. <syntaxhighlight lang="csharp">ILLabel inst = (ILLabel)cursor.Next.Operand;</syntaxhighlight> Jump to just before the method is checking whether <code>bodyChunk.owner is Player</code> (273). <syntaxhighlight lang="csharp">c.Index -= 3;</syntaxhighlight> Insert, or ''emit'', an instruction to branch unconditionally to the instruction we referenced earlier, skipping the food drain block. <syntaxhighlight lang="csharp">cursor.Emit(OpCodes.Br, inst);</syntaxhighlight> This new instruction exists between instructions 272 and 273 because the cursor's <code>Index</code> at the time was 273. This is what our hooking method looks like now: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Br, inst); } </syntaxhighlight> What we've effectively done is changed this piece of <code>Leech.Attached</code>: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> into this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (false && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> We've now achieved exactly what we wanted but, for the sake of example, we will now attach this behavior to the value of a <code>Configurable<bool></code> (e.g., from a Remix <code>OptionInterface</code>) to illustrate how to reference things in the current context for the IL context. ===Step 5: Use a delegate to access the current context from the IL context=== We'll assume that you have already set up a <code>Configurable<bool></code> and an <code>OptionInterface</code> to allow toggling it, and that it is stored in the static field <code>Options.foodDrainToggle</code>. Although it would be possible to reference <code>Options.foodDrainToggle</code> with some specific sequence of instructions, we can give the <code>ILCursor</code> a ''delegate'' that we write in the current context instead, and it will store that delegate to use again in the IL context when the method is actually run. In this case, it would look like: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); </syntaxhighlight> The type argument <code>Func<bool></code> indicates that the delegate takes no arguments (and thus removes nothing from the evaluation stack), but returns a boolean (which is then put on the stack). This needs to be placed just before the branch instruction we inserted earlier, which also needs to be changed to a conditional branch (<code>brfalse</code>) so that it actually checks the boolean we just put on the stack. Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> Note that when we emit, the cursor also moves forward, so we don't have to bump up the <code>Index</code> before inserting the next instruction. It is worth emphasizing that if any instruction we insert (including delegates) puts something on the evaluation stack, there ''must'' be an instruction that removes it from the stack (which, in this case, <code>brfalse</code> does), lest we leave the stack [[#Stack balance|unbalanced]] and cause the hook to fail. The equivalent C# code now looks like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> ===Step 6: Use a delegate to access the IL context from the current context=== We can put just about anything we want into the delegate. If we wanted to have Slugcat be [https://rainworld.miraheze.org/wiki/User:Alphappy/Live/Slowing slowed] while a Jungle Leech is attached, we could change our delegate to take in the <code>BodyChunk</code> that the original method already stored as a local: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); </syntaxhighlight> In contrast to earlier, this delegate takes a <code>BodyChunk</code> as input, which we must put on the stack before calling this delegate. Fortunately, because this <code>BodyChunk</code> is stored as a local already where our instructions are being inserted, that is very simple: <syntaxhighlight lang="csharp"> cursor.Emit(OpCodes.Ldloc, 0); </syntaxhighlight> Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Ldloc, 0); cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> The equivalent C# code now looks something like like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> Worth noting that, to achieve this slowing, we could have instead inserted a delegate after the instructions corresponding to <code>bodyChunk.owner is Player</code> instead so we don't have to make that check in our delegate. In that regard, what we've done here is inefficient, but it nonetheless demonstrates how to use something currently on the evaluation stack (that is, in the IL context) in the current context. ===Step 7: View the modified IL for debugging=== If you add <code>Debug.Log(il.ToString());</code> to the end of your hook, it will print the modified method. You will notice that this puts hundreds of lines in the log - thousands for longer methods. As such, it is best to not print this unless you are debugging. Assuming you did all of the above, you should see the following in the middle of the printout: <pre> IL_02fc: ldarg.0 IL_02fd: ldfld System.Boolean Leech::jungleLeech IL_0302: brfalse IL_050d IL_0000: ldloc V_0 IL_0000: ldc.i4 0 IL_0000: call T MonoMod.Cil.RuntimeILReferenceBag/InnerBag`1<System.Func`2<BodyChunk,System.Boolean>>::Get(System.Int32) IL_0000: call TResult MonoMod.Cil.RuntimeILReferenceBag/FastDelegateInvokers::Invoke<BodyChunk,System.Boolean>(T1,MonoMod.Cil.RuntimeILReferenceBag/FastDelegateInvokers/Func`2<T1,TResult>) IL_0000: brfalse IL_03f5 IL_0307: ldloc.0 IL_0308: callvirt PhysicalObject BodyChunk::get_owner() IL_030d: isinst Player IL_0312: brfalse IL_03f5 </pre> This shows ''offsets'' and not indices as dnSpy did. They are not sequential and not unique for our added IL, but they still allow us to make sure our hook is doing what we intended - for instance, we can see the <code>ldloc</code> and the <code>brfalse</code> we explicitly added with <code>Emit</code>. We also see three instructions that MonoMod added to call our delegate. They look messy because of how type arguments must be passed around, but all they do is *put an identifier for our delegate on the stack; *call a method to retrieve the delegate; and *call a method to invoke the delegate. For completeness, here's what these five new instructions mean: {| class="wikitable" ! OpCode ! Operand ! Meaning ! Top of stack |- | <code>ldloc</code> | <code>V_0</code> | Put local variable 0 on the stack (the first local variable defined in this method). | <code>BodyChunk bodyChunk</code> |- | <code>ldc.i4</code> | <code>0</code> | Put the integer 0 on the stack. | <code>int 0</code><br><code>BodyChunk bodyChunk</code> |- | <code>call</code> | <code>T ...InnerBag<Func<BodyChunk, bool>>::Get(...)</code> | Call MonoMod's <code>InnerBag.Get</code>. Because this takes one input, this also pops one item off the stack.<br> When our hooking method ran, MonoMod gave our delegate an identifier of <code>0</code>.<br> <code>InnerBag</code>, when given that identifier, will return our delegate.<br> Put the resulting <code>Func<BodyChunk, bool></code>, which is our delegate, on the stack. | <code>Func<BodyChunk, bool> delegate</code><br><code>BodyChunk bodyChunk</code> |- | <code>call</code> | <code>TResult ...FastDelegateInvokers::Invoke<BodyChunk, bool>(...)</code> | Call MonoMod's <code>FastDelegateInvokers.Invoke</code>. This will pop a number of items off the stack equal to the number of arguments to the delegate plus one.<br> In our case, it will take two arguments, which are expected to be the delegate and a <code>BodyChunk</code>.<br> MonoMod will then ''invoke'' our delegate, passing the <code>BodyChunk</code> as the sole argument.<br> Put the resulting <code>bool</code> (the <code>TResult</code> of our delegate) on the stack. | <code>bool delegate(BodyChunk bodyChunk)</code> |- | <code>brfalse</code> | <code>IL_03f5</code> | Pop an item off the stack. If it is false, go to the instruction at offset 03f5. Offset 03f5 is just after <code>if (bodyChunk.owner is Player & ...) { ... }</code>. | irrelevant |} Note that the five instructions we've added collectively push to and pop from the stack the same number of times (four, in this case). This is necessary for [[#Stack balance|stack balance]]. ==Notes== ===Stack balance=== If you get an exception telling you that <code>ret</code> is an invalid OpCode, you've left the stack unbalanced. The number of objects on the stack before and after a method executes must be equal. If the stack is ''unbalanced'' - that is, more things are placed on the stack than are removed for a given method, or vice versa - the IL hook will fail. It is therefore important to understand [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields how each OpCode interacts with the stack]. Most instructions pop one object, push one object, or both - but some instructions may pop or push more than one object depending on their operand. e68b0fc43740e81a2d0e11525d49de9c413aae3b 559 558 2023-10-08T18:15:15Z Alphappy 121 add notes on find, trygoto, and tryfind; add exact exception for stack imbalnace; add notes on failure to match along with the most common exception wikitext text/x-wiki '''IL hooking''', or '''intermediate-language hooking''', is an alternative to standard event hooking that allows for injection of arbitrary instructions within a method. ==Prerequisites== It is assumed that you fully understand how to use a standard event hook (<code>On</code>) as described at [[BepInPlugins]]. Additionally, it will be helpful to understand the concept of an [[w:Stack (abstract data type)|evaluation stack]], which is how objects are stored at the intermediate level. [[w:High-level programming language|High-level programming languages]] like C# abstract away the evaluation stack and allow for the more human-friendly use of named variables. This will be a little more complicated in IL - objects can only be ''pushed'' to the top of the stack or ''popped'' off the top of the stack; it is not possible to access anywhere else in the stack. It is highly recommended to have a convenient way to view the IL instructions of Rain World's code. dnSpy can do this - right-click a line of code, and select ''Edit IL Instructions...'' We will cover how to interpret this information later. You will need to add several additional references to your project for IL hooking to work: *<code>Mono.Cecil.dll</code> *<code>Mono.Cecil.Mdb.dll</code> *<code>Mono.Cecil.Pdb.dll</code> *<code>Mono.Cecil.Rocks.dll</code> *<code>MonoMod.Common.dll</code> *<code>MonoMod.RuntimeDetour.dll</code> *<code>MonoMod.Utils.dll</code> These are normally in <code>Steam\steamapps\common\Rain World\RainWorld_Data\Managed</code> (although it is again recommended to copy them somewhere else first). This guide is intended to be self-sufficient, but see also [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ Risk of Thunder's guide to IL hooking] for another perspective and more examples. A list of all IL instruction OpCodes and what they do can be found on [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields Microsoft's documentation page]. This is not required reading, but it will be a handy reference. Everything in this guide is tested with Visual Studio 2022 17.7.0, .NET Framework 4.8.04084, and Rain World 1.9.07b. Newer versions could very well break something. ==Overview== Like standard event hooking, IL hooking targets a specific method in Rain World's assembly. There are a few key differences: *A standard event hook receives references to the original method <code>orig</code> and every argument that it would have received (including <code>this</code> if non-static, which the hook receives as <code>self</code> by default). An IL hook receives only an <code>ILContext</code> which is used to navigate the method's IL instructions. *The code you write in a standard event hook is run every time the game calls the hooked method (assuming no other mods hook that method and forgo the <code>orig</code> call). In an IL hook, the code you write is run only once when the mod is initialized, but the effect of this code is to essentially modify the original method directly. *A standard event hook can essentially only cause changes at the beginning or end of an existing method. An IL hook can cause changes inside a method. A mod with an IL hook is still a BepInPlugin. [[BepInPlugins#Testing your code|Building it]], creating a [[Downpour Reference/BepInEx Files|mod directory]], and [[Downpour Reference/Mod Directories|including other files]] is still the same process. ==Procedure== As an example, we're going to hook <code>Leech.Attached</code> to prevent Jungle Leeches from draining Slugcat's food. As the relevant code is in the middle of the method, a standard event hook won't work (at least not easily). ===Step 1: Create an IL hook=== IL hooks are created similarly to standard event hooks. First, we must import a couple of things (in addition to what you would import for standard event hooks): <syntaxhighlight lang="csharp"> using Mono.Cecil.Cil; using MonoMod.Cil; </syntaxhighlight> Next, you can auto-generate the hooking method just as you would with a standard event hook. Pressing TAB after <code>+=</code> will create the hooking method automatically. <syntaxhighlight lang="csharp"> private void OnEnable() { IL.Leech.Attached += Leech_Attached; } private void Leech_Attached(ILContext il) { throw new NotImplementedException(); } </syntaxhighlight> You will also need to instantiate the cursor: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); } </syntaxhighlight> ===Step 2: Determine what to modify=== Before we can proceed, we need to know how to actually modify the method to get the effect we want. In <code>Leech.Attached</code>, the method checks whether the Leech in question is a Jungle Leech, then whether the creature it is attached to is a <code>Player</code> (Slugcat): <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> Ultimately, we want the method to ''not'' check whether the creature is a <code>Player</code> and just skip the entire following block of code, while is responsible for the food drain. Viewing the IL for this method reveals the following: <pre> 270 02FC ldarg.0 271 02FD ldfld bool Leech::jungleLeech 272 0302 brfalse 414 (050D) ldarg.0 273 0307 ldloc.0 274 0308 callvirt instance class PhysicalObject BodyChunk::get_owner() 275 030D isinst Player 276 0312 brfalse 340 (03F5) ldloc.0 </pre> Each row is an ''instruction''. The first column is the ''index'' of the instruction, which will aid in discussion of where we want to make our modifications. The third column is the ''OpCode'' for that instruction, which is very generally what the instruction does. A list of all OpCodes and what they do can be found on [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields Microsoft's documentation page]. The final column is the ''operand'' for the instruction. These particular instructions mean the following: {| class="wikitable" ! Index ! OpCode ! Operand ! Meaning ! Top of stack |- | 270 | <code>ldarg.0</code> | | Put argument 0 on the evaluation stack. In a non-static class method, argument 0 is always a reference to <code>this</code>. | <code>Leech this</code> |- | 271 | <code>ldfld</code> | <code>bool Leech::jungleLeech</code> | Pop an item off the stack, access its <code>jungleLeech</code> field, and put that <code>bool</code> on the stack. | <code>bool this.jungleLeech</code> |- | 272 | <code>brfalse</code> | <code>414</code> | Pop an item off the stack. If it is false, go to the instruction at index 414. Index 414 is just after the entire <code>if (this.jungleLeech) { ... }</code> block. | irrelevant |- | 273 | <code>ldloc.0</code> | | Put local variable 0 on the stack (the first local variable defined in this method). | <code>BodyChunk bodyChunk</code> |- | 274 | <code>callvirt</code> | <code>instance class PhysicalObject BodyChunk::get_owner()</code> | Pop an item off the stack, and call its <code>get_owner</code> property getter, and put the result on the stack. | <code>PhysicalObject bodyChunk.owner</code> |- | 275 | <code>isinst</code> | <code>Player</code> | Pop an item off the stack. Put a <code>bool</code> on the stack corresponding to whether it is an instance of <code>Player</code>. | <code>bool (bodyChunk.owner is Player)</code> |- | 276 | <code>brfalse</code> | <code>340</code> | Pop an item off the stack. If it is false, go to the instruction at index 340. Index 340 is just after <code>if (bodyChunk.owner is Player & ...) { ... }</code>. | irrelevant |} Instructions 270 and 271 correspond to <code>if (this.JungleLeech)</code>, with 272 skipping the entire code block if it is false. Instructions 273 through 275 correspond to <code>if (bodyChunk.owner is Player)</code>, with 276 skipping just the code block that affects only Slugcat if it is false. While the second conditional here is compound, conditionals are broken into their individual parts and tested individually at the IL level. This is how [[w:Short-circuit evaluation|short-circuit evaluation]] is implemented: <code>(bodyChunk.owner is Player && somethingElse)</code> has no need to evaluate <code>somethingElse</code> if <code>bodyChunk.owner is Player</code> is false. We want to have the code not even bother with checking if <code>bodyChunk.owner is Player</code> and always skip the Slugcat-specific block (which is what instruction 276 does). ===Step 3: Find the instructions of interest=== While we ''could'' tell the cursor to move directly to the index of the instructions we want to modify, that won't work reliably if any other mod IL hooks this method and changes the number of instructions. Instead, the better procedure is to ''search'' for a sequence of instructions. How many instructions should be included in this sequence is subjective. Too few, and there's a chance your hook will land somewhere it shouldn't; too many, and there's a chance another hook will modify code inside what you are trying to match, and your hook matches nothing and fails. In this example, matching instructions 270 through 276 should suffice. We tell our <code>ILCursor</code> to search for a specific sequence of instructions with <code>GotoNext</code>: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); } </syntaxhighlight> This will tell the cursor to find an <code>ldarg.0</code> instruction, followed by a <code>ldfld</code> instruction with <code>jungleLeech</code> as the operand, et cetera. Crucially, it must find all seven of these instructions in order with no gaps. If successful, this will place the cursor at index 270 - the beginning of the instruction sequence we searched for. If it fails, an exception is thrown and this hook does not get applied. ===Step 4: Modify the instructions=== From earlier, we want to insert instructions to make the method skip checking whether <code>bodyChunk.owner is Player</code> and the following block. This just involves inserting an unconditional branch instruction. However, we have to tell it ''where'' to branch to, so we have one extra step of grabbing a reference to the instruction we want to branch to. Because we told the cursor to look for the entire sequence of 7 instructions, we can be sure they all exist here, and we don't have to use <code>GotoNext</code> to search again. We do the following to achieve this: Jump to the instruction that will skip the food drain code (276). <syntaxhighlight lang="csharp">c.Index += 6;</syntaxhighlight> Grab the operand of this instruction and store it locally. The operand of a branch instruction is always another <code>ILLabel</code> which points to the instruction of interest. <syntaxhighlight lang="csharp">ILLabel inst = (ILLabel)cursor.Next.Operand;</syntaxhighlight> Jump to just before the method is checking whether <code>bodyChunk.owner is Player</code> (273). <syntaxhighlight lang="csharp">c.Index -= 3;</syntaxhighlight> Insert, or ''emit'', an instruction to branch unconditionally to the instruction we referenced earlier, skipping the food drain block. <syntaxhighlight lang="csharp">cursor.Emit(OpCodes.Br, inst);</syntaxhighlight> This new instruction exists between instructions 272 and 273 because the cursor's <code>Index</code> at the time was 273. This is what our hooking method looks like now: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Br, inst); } </syntaxhighlight> What we've effectively done is changed this piece of <code>Leech.Attached</code>: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> into this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (false && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> We've now achieved exactly what we wanted but, for the sake of example, we will now attach this behavior to the value of a <code>Configurable<bool></code> (e.g., from a Remix <code>OptionInterface</code>) to illustrate how to reference things in the current context for the IL context. ===Step 5: Use a delegate to access the current context from the IL context=== We'll assume that you have already set up a <code>Configurable<bool></code> and an <code>OptionInterface</code> to allow toggling it, and that it is stored in the static field <code>Options.foodDrainToggle</code>. Although it would be possible to reference <code>Options.foodDrainToggle</code> with some specific sequence of instructions, we can give the <code>ILCursor</code> a ''delegate'' that we write in the current context instead, and it will store that delegate to use again in the IL context when the method is actually run. In this case, it would look like: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); </syntaxhighlight> The type argument <code>Func<bool></code> indicates that the delegate takes no arguments (and thus removes nothing from the evaluation stack), but returns a boolean (which is then put on the stack). This needs to be placed just before the branch instruction we inserted earlier, which also needs to be changed to a conditional branch (<code>brfalse</code>) so that it actually checks the boolean we just put on the stack. Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> Note that when we emit, the cursor also moves forward, so we don't have to bump up the <code>Index</code> before inserting the next instruction. It is worth emphasizing that if any instruction we insert (including delegates) puts something on the evaluation stack, there ''must'' be an instruction that removes it from the stack (which, in this case, <code>brfalse</code> does), lest we leave the stack [[#Stack balance|unbalanced]] and cause the hook to fail. The equivalent C# code now looks like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> ===Step 6: Use a delegate to access the IL context from the current context=== We can put just about anything we want into the delegate. If we wanted to have Slugcat be [https://rainworld.miraheze.org/wiki/User:Alphappy/Live/Slowing slowed] while a Jungle Leech is attached, we could change our delegate to take in the <code>BodyChunk</code> that the original method already stored as a local: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); </syntaxhighlight> In contrast to earlier, this delegate takes a <code>BodyChunk</code> as input, which we must put on the stack before calling this delegate. Fortunately, because this <code>BodyChunk</code> is stored as a local already where our instructions are being inserted, that is very simple: <syntaxhighlight lang="csharp"> cursor.Emit(OpCodes.Ldloc, 0); </syntaxhighlight> Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Ldloc, 0); cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> The equivalent C# code now looks something like like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> Worth noting that, to achieve this slowing, we could have instead inserted a delegate after the instructions corresponding to <code>bodyChunk.owner is Player</code> instead so we don't have to make that check in our delegate. In that regard, what we've done here is inefficient, but it nonetheless demonstrates how to use something currently on the evaluation stack (that is, in the IL context) in the current context. ===Step 7: View the modified IL for debugging=== If you add <code>Debug.Log(il.ToString());</code> to the end of your hook, it will print the modified method. You will notice that this puts hundreds of lines in the log - thousands for longer methods. As such, it is best to not print this unless you are debugging. Assuming you did all of the above, you should see the following in the middle of the printout: <pre> IL_02fc: ldarg.0 IL_02fd: ldfld System.Boolean Leech::jungleLeech IL_0302: brfalse IL_050d IL_0000: ldloc V_0 IL_0000: ldc.i4 0 IL_0000: call T MonoMod.Cil.RuntimeILReferenceBag/InnerBag`1<System.Func`2<BodyChunk,System.Boolean>>::Get(System.Int32) IL_0000: call TResult MonoMod.Cil.RuntimeILReferenceBag/FastDelegateInvokers::Invoke<BodyChunk,System.Boolean>(T1,MonoMod.Cil.RuntimeILReferenceBag/FastDelegateInvokers/Func`2<T1,TResult>) IL_0000: brfalse IL_03f5 IL_0307: ldloc.0 IL_0308: callvirt PhysicalObject BodyChunk::get_owner() IL_030d: isinst Player IL_0312: brfalse IL_03f5 </pre> This shows ''offsets'' and not indices as dnSpy did. They are not sequential and not unique for our added IL, but they still allow us to make sure our hook is doing what we intended - for instance, we can see the <code>ldloc</code> and the <code>brfalse</code> we explicitly added with <code>Emit</code>. We also see three instructions that MonoMod added to call our delegate. They look messy because of how type arguments must be passed around, but all they do is *put an identifier for our delegate on the stack; *call a method to retrieve the delegate; and *call a method to invoke the delegate. For completeness, here's what these five new instructions mean: {| class="wikitable" ! OpCode ! Operand ! Meaning ! Top of stack |- | <code>ldloc</code> | <code>V_0</code> | Put local variable 0 on the stack (the first local variable defined in this method). | <code>BodyChunk bodyChunk</code> |- | <code>ldc.i4</code> | <code>0</code> | Put the integer 0 on the stack. | <code>int 0</code><br><code>BodyChunk bodyChunk</code> |- | <code>call</code> | <code>T ...InnerBag<Func<BodyChunk, bool>>::Get(...)</code> | Call MonoMod's <code>InnerBag.Get</code>. Because this takes one input, this also pops one item off the stack.<br> When our hooking method ran, MonoMod gave our delegate an identifier of <code>0</code>.<br> <code>InnerBag</code>, when given that identifier, will return our delegate.<br> Put the resulting <code>Func<BodyChunk, bool></code>, which is our delegate, on the stack. | <code>Func<BodyChunk, bool> delegate</code><br><code>BodyChunk bodyChunk</code> |- | <code>call</code> | <code>TResult ...FastDelegateInvokers::Invoke<BodyChunk, bool>(...)</code> | Call MonoMod's <code>FastDelegateInvokers.Invoke</code>. This will pop a number of items off the stack equal to the number of arguments to the delegate plus one.<br> In our case, it will take two arguments, which are expected to be the delegate and a <code>BodyChunk</code>.<br> MonoMod will then ''invoke'' our delegate, passing the <code>BodyChunk</code> as the sole argument.<br> Put the resulting <code>bool</code> (the <code>TResult</code> of our delegate) on the stack. | <code>bool delegate(BodyChunk bodyChunk)</code> |- | <code>brfalse</code> | <code>IL_03f5</code> | Pop an item off the stack. If it is false, go to the instruction at offset 03f5. Offset 03f5 is just after <code>if (bodyChunk.owner is Player & ...) { ... }</code>. | irrelevant |} Note that the five instructions we've added collectively push to and pop from the stack the same number of times (four, in this case). This is necessary for [[#Stack balance|stack balance]]. ==Notes== ===Stack balance=== If you get the exception <code>System.InvalidProgramException: Invalid IL code in ...: ret</code>, you've left the stack unbalanced. The number of objects on the stack before and after a method executes must be equal. If the stack is ''unbalanced'' - that is, more things are placed on the stack than are removed for a given method, or vice versa - the IL hook will fail. It is therefore important to understand [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields how each OpCode interacts with the stack]. Most instructions pop one object, push one object, or both - but some instructions may pop or push more than one object depending on their operand. ===Failure to match=== If you get the exception <code>System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.</code>, your cursor failed to find the instructions requested in a <code>Goto</code>. Most likely, it means that you've just specified one of your <code>Match</code>es incorrectly. This can also happen if you try to match a block of instructions that another IL hook modifies before yours. This is an unlikely circumstance, but becomes more likely as the number of instructions to match increases. ===Find=== <code>ILCursor</code> offers <code>FindNext</code> and <code>FindPrev</code> as an alternative to the <code>Goto</code> methods. While <code>Goto</code> requires no gaps in the sequence of requested instructions, <code>Find</code> allows any gaps, as long as at finds the instructions in the requested order. For most hooks you write, you will ''not'' want to use <code>Find</code> methods without very carefully considering how specific your searched instructions are. For instance, if you try to <code>Find</code> the instructions associated with putting <code>this.abstractCreature.creatureTemplate</code> on the stack, it might first find an earlier place where <code>this.abstractCreature.personality</code> is put on the stack instead, and then ''eventually'' find the instructions that load <code>creatureTemplate</code> onto the stack. The cursor, however, will be at the ''first'' matched instruction - right before <code>this.abstractCreature.personality</code>. ===TryGoto and TryFind=== <code>ILCursor</code> offers <code>Try</code> versions of <code>Goto</code> and <code>Find</code> methods which will not raise an exception if they can't find the instructions you requested. For most hooks you write, you will ''not'' want to use the <code>Try</code> versions (in general, silent exception suppression is a bad thing). The cursor will simply not move if it can't find what you requested, meaning your next commands to inject new instructions will likely fail or cause unintended behavior since they are not where you intended them to be. d71f06bdec77d507cc39d99c39dd00850512cd01 560 559 2023-10-08T18:33:23Z Alphappy 121 /* Find */ reword example to be more specific wikitext text/x-wiki '''IL hooking''', or '''intermediate-language hooking''', is an alternative to standard event hooking that allows for injection of arbitrary instructions within a method. ==Prerequisites== It is assumed that you fully understand how to use a standard event hook (<code>On</code>) as described at [[BepInPlugins]]. Additionally, it will be helpful to understand the concept of an [[w:Stack (abstract data type)|evaluation stack]], which is how objects are stored at the intermediate level. [[w:High-level programming language|High-level programming languages]] like C# abstract away the evaluation stack and allow for the more human-friendly use of named variables. This will be a little more complicated in IL - objects can only be ''pushed'' to the top of the stack or ''popped'' off the top of the stack; it is not possible to access anywhere else in the stack. It is highly recommended to have a convenient way to view the IL instructions of Rain World's code. dnSpy can do this - right-click a line of code, and select ''Edit IL Instructions...'' We will cover how to interpret this information later. You will need to add several additional references to your project for IL hooking to work: *<code>Mono.Cecil.dll</code> *<code>Mono.Cecil.Mdb.dll</code> *<code>Mono.Cecil.Pdb.dll</code> *<code>Mono.Cecil.Rocks.dll</code> *<code>MonoMod.Common.dll</code> *<code>MonoMod.RuntimeDetour.dll</code> *<code>MonoMod.Utils.dll</code> These are normally in <code>Steam\steamapps\common\Rain World\RainWorld_Data\Managed</code> (although it is again recommended to copy them somewhere else first). This guide is intended to be self-sufficient, but see also [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ Risk of Thunder's guide to IL hooking] for another perspective and more examples. A list of all IL instruction OpCodes and what they do can be found on [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields Microsoft's documentation page]. This is not required reading, but it will be a handy reference. Everything in this guide is tested with Visual Studio 2022 17.7.0, .NET Framework 4.8.04084, and Rain World 1.9.07b. Newer versions could very well break something. ==Overview== Like standard event hooking, IL hooking targets a specific method in Rain World's assembly. There are a few key differences: *A standard event hook receives references to the original method <code>orig</code> and every argument that it would have received (including <code>this</code> if non-static, which the hook receives as <code>self</code> by default). An IL hook receives only an <code>ILContext</code> which is used to navigate the method's IL instructions. *The code you write in a standard event hook is run every time the game calls the hooked method (assuming no other mods hook that method and forgo the <code>orig</code> call). In an IL hook, the code you write is run only once when the mod is initialized, but the effect of this code is to essentially modify the original method directly. *A standard event hook can essentially only cause changes at the beginning or end of an existing method. An IL hook can cause changes inside a method. A mod with an IL hook is still a BepInPlugin. [[BepInPlugins#Testing your code|Building it]], creating a [[Downpour Reference/BepInEx Files|mod directory]], and [[Downpour Reference/Mod Directories|including other files]] is still the same process. ==Procedure== As an example, we're going to hook <code>Leech.Attached</code> to prevent Jungle Leeches from draining Slugcat's food. As the relevant code is in the middle of the method, a standard event hook won't work (at least not easily). ===Step 1: Create an IL hook=== IL hooks are created similarly to standard event hooks. First, we must import a couple of things (in addition to what you would import for standard event hooks): <syntaxhighlight lang="csharp"> using Mono.Cecil.Cil; using MonoMod.Cil; </syntaxhighlight> Next, you can auto-generate the hooking method just as you would with a standard event hook. Pressing TAB after <code>+=</code> will create the hooking method automatically. <syntaxhighlight lang="csharp"> private void OnEnable() { IL.Leech.Attached += Leech_Attached; } private void Leech_Attached(ILContext il) { throw new NotImplementedException(); } </syntaxhighlight> You will also need to instantiate the cursor: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); } </syntaxhighlight> ===Step 2: Determine what to modify=== Before we can proceed, we need to know how to actually modify the method to get the effect we want. In <code>Leech.Attached</code>, the method checks whether the Leech in question is a Jungle Leech, then whether the creature it is attached to is a <code>Player</code> (Slugcat): <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> Ultimately, we want the method to ''not'' check whether the creature is a <code>Player</code> and just skip the entire following block of code, while is responsible for the food drain. Viewing the IL for this method reveals the following: <pre> 270 02FC ldarg.0 271 02FD ldfld bool Leech::jungleLeech 272 0302 brfalse 414 (050D) ldarg.0 273 0307 ldloc.0 274 0308 callvirt instance class PhysicalObject BodyChunk::get_owner() 275 030D isinst Player 276 0312 brfalse 340 (03F5) ldloc.0 </pre> Each row is an ''instruction''. The first column is the ''index'' of the instruction, which will aid in discussion of where we want to make our modifications. The third column is the ''OpCode'' for that instruction, which is very generally what the instruction does. A list of all OpCodes and what they do can be found on [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields Microsoft's documentation page]. The final column is the ''operand'' for the instruction. These particular instructions mean the following: {| class="wikitable" ! Index ! OpCode ! Operand ! Meaning ! Top of stack |- | 270 | <code>ldarg.0</code> | | Put argument 0 on the evaluation stack. In a non-static class method, argument 0 is always a reference to <code>this</code>. | <code>Leech this</code> |- | 271 | <code>ldfld</code> | <code>bool Leech::jungleLeech</code> | Pop an item off the stack, access its <code>jungleLeech</code> field, and put that <code>bool</code> on the stack. | <code>bool this.jungleLeech</code> |- | 272 | <code>brfalse</code> | <code>414</code> | Pop an item off the stack. If it is false, go to the instruction at index 414. Index 414 is just after the entire <code>if (this.jungleLeech) { ... }</code> block. | irrelevant |- | 273 | <code>ldloc.0</code> | | Put local variable 0 on the stack (the first local variable defined in this method). | <code>BodyChunk bodyChunk</code> |- | 274 | <code>callvirt</code> | <code>instance class PhysicalObject BodyChunk::get_owner()</code> | Pop an item off the stack, and call its <code>get_owner</code> property getter, and put the result on the stack. | <code>PhysicalObject bodyChunk.owner</code> |- | 275 | <code>isinst</code> | <code>Player</code> | Pop an item off the stack. Put a <code>bool</code> on the stack corresponding to whether it is an instance of <code>Player</code>. | <code>bool (bodyChunk.owner is Player)</code> |- | 276 | <code>brfalse</code> | <code>340</code> | Pop an item off the stack. If it is false, go to the instruction at index 340. Index 340 is just after <code>if (bodyChunk.owner is Player & ...) { ... }</code>. | irrelevant |} Instructions 270 and 271 correspond to <code>if (this.JungleLeech)</code>, with 272 skipping the entire code block if it is false. Instructions 273 through 275 correspond to <code>if (bodyChunk.owner is Player)</code>, with 276 skipping just the code block that affects only Slugcat if it is false. While the second conditional here is compound, conditionals are broken into their individual parts and tested individually at the IL level. This is how [[w:Short-circuit evaluation|short-circuit evaluation]] is implemented: <code>(bodyChunk.owner is Player && somethingElse)</code> has no need to evaluate <code>somethingElse</code> if <code>bodyChunk.owner is Player</code> is false. We want to have the code not even bother with checking if <code>bodyChunk.owner is Player</code> and always skip the Slugcat-specific block (which is what instruction 276 does). ===Step 3: Find the instructions of interest=== While we ''could'' tell the cursor to move directly to the index of the instructions we want to modify, that won't work reliably if any other mod IL hooks this method and changes the number of instructions. Instead, the better procedure is to ''search'' for a sequence of instructions. How many instructions should be included in this sequence is subjective. Too few, and there's a chance your hook will land somewhere it shouldn't; too many, and there's a chance another hook will modify code inside what you are trying to match, and your hook matches nothing and fails. In this example, matching instructions 270 through 276 should suffice. We tell our <code>ILCursor</code> to search for a specific sequence of instructions with <code>GotoNext</code>: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); } </syntaxhighlight> This will tell the cursor to find an <code>ldarg.0</code> instruction, followed by a <code>ldfld</code> instruction with <code>jungleLeech</code> as the operand, et cetera. Crucially, it must find all seven of these instructions in order with no gaps. If successful, this will place the cursor at index 270 - the beginning of the instruction sequence we searched for. If it fails, an exception is thrown and this hook does not get applied. ===Step 4: Modify the instructions=== From earlier, we want to insert instructions to make the method skip checking whether <code>bodyChunk.owner is Player</code> and the following block. This just involves inserting an unconditional branch instruction. However, we have to tell it ''where'' to branch to, so we have one extra step of grabbing a reference to the instruction we want to branch to. Because we told the cursor to look for the entire sequence of 7 instructions, we can be sure they all exist here, and we don't have to use <code>GotoNext</code> to search again. We do the following to achieve this: Jump to the instruction that will skip the food drain code (276). <syntaxhighlight lang="csharp">c.Index += 6;</syntaxhighlight> Grab the operand of this instruction and store it locally. The operand of a branch instruction is always another <code>ILLabel</code> which points to the instruction of interest. <syntaxhighlight lang="csharp">ILLabel inst = (ILLabel)cursor.Next.Operand;</syntaxhighlight> Jump to just before the method is checking whether <code>bodyChunk.owner is Player</code> (273). <syntaxhighlight lang="csharp">c.Index -= 3;</syntaxhighlight> Insert, or ''emit'', an instruction to branch unconditionally to the instruction we referenced earlier, skipping the food drain block. <syntaxhighlight lang="csharp">cursor.Emit(OpCodes.Br, inst);</syntaxhighlight> This new instruction exists between instructions 272 and 273 because the cursor's <code>Index</code> at the time was 273. This is what our hooking method looks like now: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Br, inst); } </syntaxhighlight> What we've effectively done is changed this piece of <code>Leech.Attached</code>: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> into this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (false && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> We've now achieved exactly what we wanted but, for the sake of example, we will now attach this behavior to the value of a <code>Configurable<bool></code> (e.g., from a Remix <code>OptionInterface</code>) to illustrate how to reference things in the current context for the IL context. ===Step 5: Use a delegate to access the current context from the IL context=== We'll assume that you have already set up a <code>Configurable<bool></code> and an <code>OptionInterface</code> to allow toggling it, and that it is stored in the static field <code>Options.foodDrainToggle</code>. Although it would be possible to reference <code>Options.foodDrainToggle</code> with some specific sequence of instructions, we can give the <code>ILCursor</code> a ''delegate'' that we write in the current context instead, and it will store that delegate to use again in the IL context when the method is actually run. In this case, it would look like: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); </syntaxhighlight> The type argument <code>Func<bool></code> indicates that the delegate takes no arguments (and thus removes nothing from the evaluation stack), but returns a boolean (which is then put on the stack). This needs to be placed just before the branch instruction we inserted earlier, which also needs to be changed to a conditional branch (<code>brfalse</code>) so that it actually checks the boolean we just put on the stack. Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> Note that when we emit, the cursor also moves forward, so we don't have to bump up the <code>Index</code> before inserting the next instruction. It is worth emphasizing that if any instruction we insert (including delegates) puts something on the evaluation stack, there ''must'' be an instruction that removes it from the stack (which, in this case, <code>brfalse</code> does), lest we leave the stack [[#Stack balance|unbalanced]] and cause the hook to fail. The equivalent C# code now looks like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> ===Step 6: Use a delegate to access the IL context from the current context=== We can put just about anything we want into the delegate. If we wanted to have Slugcat be [https://rainworld.miraheze.org/wiki/User:Alphappy/Live/Slowing slowed] while a Jungle Leech is attached, we could change our delegate to take in the <code>BodyChunk</code> that the original method already stored as a local: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); </syntaxhighlight> In contrast to earlier, this delegate takes a <code>BodyChunk</code> as input, which we must put on the stack before calling this delegate. Fortunately, because this <code>BodyChunk</code> is stored as a local already where our instructions are being inserted, that is very simple: <syntaxhighlight lang="csharp"> cursor.Emit(OpCodes.Ldloc, 0); </syntaxhighlight> Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Ldloc, 0); cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> The equivalent C# code now looks something like like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> Worth noting that, to achieve this slowing, we could have instead inserted a delegate after the instructions corresponding to <code>bodyChunk.owner is Player</code> instead so we don't have to make that check in our delegate. In that regard, what we've done here is inefficient, but it nonetheless demonstrates how to use something currently on the evaluation stack (that is, in the IL context) in the current context. ===Step 7: View the modified IL for debugging=== If you add <code>Debug.Log(il.ToString());</code> to the end of your hook, it will print the modified method. You will notice that this puts hundreds of lines in the log - thousands for longer methods. As such, it is best to not print this unless you are debugging. Assuming you did all of the above, you should see the following in the middle of the printout: <pre> IL_02fc: ldarg.0 IL_02fd: ldfld System.Boolean Leech::jungleLeech IL_0302: brfalse IL_050d IL_0000: ldloc V_0 IL_0000: ldc.i4 0 IL_0000: call T MonoMod.Cil.RuntimeILReferenceBag/InnerBag`1<System.Func`2<BodyChunk,System.Boolean>>::Get(System.Int32) IL_0000: call TResult MonoMod.Cil.RuntimeILReferenceBag/FastDelegateInvokers::Invoke<BodyChunk,System.Boolean>(T1,MonoMod.Cil.RuntimeILReferenceBag/FastDelegateInvokers/Func`2<T1,TResult>) IL_0000: brfalse IL_03f5 IL_0307: ldloc.0 IL_0308: callvirt PhysicalObject BodyChunk::get_owner() IL_030d: isinst Player IL_0312: brfalse IL_03f5 </pre> This shows ''offsets'' and not indices as dnSpy did. They are not sequential and not unique for our added IL, but they still allow us to make sure our hook is doing what we intended - for instance, we can see the <code>ldloc</code> and the <code>brfalse</code> we explicitly added with <code>Emit</code>. We also see three instructions that MonoMod added to call our delegate. They look messy because of how type arguments must be passed around, but all they do is *put an identifier for our delegate on the stack; *call a method to retrieve the delegate; and *call a method to invoke the delegate. For completeness, here's what these five new instructions mean: {| class="wikitable" ! OpCode ! Operand ! Meaning ! Top of stack |- | <code>ldloc</code> | <code>V_0</code> | Put local variable 0 on the stack (the first local variable defined in this method). | <code>BodyChunk bodyChunk</code> |- | <code>ldc.i4</code> | <code>0</code> | Put the integer 0 on the stack. | <code>int 0</code><br><code>BodyChunk bodyChunk</code> |- | <code>call</code> | <code>T ...InnerBag<Func<BodyChunk, bool>>::Get(...)</code> | Call MonoMod's <code>InnerBag.Get</code>. Because this takes one input, this also pops one item off the stack.<br> When our hooking method ran, MonoMod gave our delegate an identifier of <code>0</code>.<br> <code>InnerBag</code>, when given that identifier, will return our delegate.<br> Put the resulting <code>Func<BodyChunk, bool></code>, which is our delegate, on the stack. | <code>Func<BodyChunk, bool> delegate</code><br><code>BodyChunk bodyChunk</code> |- | <code>call</code> | <code>TResult ...FastDelegateInvokers::Invoke<BodyChunk, bool>(...)</code> | Call MonoMod's <code>FastDelegateInvokers.Invoke</code>. This will pop a number of items off the stack equal to the number of arguments to the delegate plus one.<br> In our case, it will take two arguments, which are expected to be the delegate and a <code>BodyChunk</code>.<br> MonoMod will then ''invoke'' our delegate, passing the <code>BodyChunk</code> as the sole argument.<br> Put the resulting <code>bool</code> (the <code>TResult</code> of our delegate) on the stack. | <code>bool delegate(BodyChunk bodyChunk)</code> |- | <code>brfalse</code> | <code>IL_03f5</code> | Pop an item off the stack. If it is false, go to the instruction at offset 03f5. Offset 03f5 is just after <code>if (bodyChunk.owner is Player & ...) { ... }</code>. | irrelevant |} Note that the five instructions we've added collectively push to and pop from the stack the same number of times (four, in this case). This is necessary for [[#Stack balance|stack balance]]. ==Notes== ===Stack balance=== If you get the exception <code>System.InvalidProgramException: Invalid IL code in ...: ret</code>, you've left the stack unbalanced. The number of objects on the stack before and after a method executes must be equal. If the stack is ''unbalanced'' - that is, more things are placed on the stack than are removed for a given method, or vice versa - the IL hook will fail. It is therefore important to understand [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields how each OpCode interacts with the stack]. Most instructions pop one object, push one object, or both - but some instructions may pop or push more than one object depending on their operand. ===Failure to match=== If you get the exception <code>System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.</code>, your cursor failed to find the instructions requested in a <code>Goto</code>. Most likely, it means that you've just specified one of your <code>Match</code>es incorrectly. This can also happen if you try to match a block of instructions that another IL hook modifies before yours. This is an unlikely circumstance, but becomes more likely as the number of instructions to match increases. ===Find=== <code>ILCursor</code> offers <code>FindNext</code> and <code>FindPrev</code> as an alternative to the <code>Goto</code> methods. While <code>Goto</code> requires no gaps in the sequence of requested instructions, <code>Find</code> allows any gaps, as long as at finds the instructions in the requested order. For most hooks you write, you will ''not'' want to use <code>Find</code> methods without very carefully considering how specific your searched instructions are. For instance, if you try to <code>Find</code> the instructions associated with putting <code>this.abstractCreature</code> on the stack - which involves <code>ldarg.0</code> as the first instruction - the cursor will land on the first time that <code>this</code> is put on the stack for any reason, so long as the remaining <code>ldfld</code> instruction associated with <code>this.abstractCreature</code> is ''somewhere'' further along in the method. Of course, if <code>this.abstractCreature</code> ''happens'' to be the first time <code>this</code> is put on the stack, it will still work. ===TryGoto and TryFind=== <code>ILCursor</code> offers <code>Try</code> versions of <code>Goto</code> and <code>Find</code> methods which will not raise an exception if they can't find the instructions you requested. For most hooks you write, you will ''not'' want to use the <code>Try</code> versions (in general, silent exception suppression is a bad thing). The cursor will simply not move if it can't find what you requested, meaning your next commands to inject new instructions will likely fail or cause unintended behavior since they are not where you intended them to be. 4cd4f140e7ea9e4523c024be248922b3a437cf5b 561 560 2023-10-08T21:25:24Z Alphappy 121 add examples of matching to be expanded upon later wikitext text/x-wiki '''IL hooking''', or '''intermediate-language hooking''', is an alternative to standard event hooking that allows for injection of arbitrary instructions within a method. ==Prerequisites== It is assumed that you fully understand how to use a standard event hook (<code>On</code>) as described at [[BepInPlugins]]. Additionally, it will be helpful to understand the concept of an [[w:Stack (abstract data type)|evaluation stack]], which is how objects are stored at the intermediate level. [[w:High-level programming language|High-level programming languages]] like C# abstract away the evaluation stack and allow for the more human-friendly use of named variables. This will be a little more complicated in IL - objects can only be ''pushed'' to the top of the stack or ''popped'' off the top of the stack; it is not possible to access anywhere else in the stack. It is highly recommended to have a convenient way to view the IL instructions of Rain World's code. dnSpy can do this - right-click a line of code, and select ''Edit IL Instructions...'' We will cover how to interpret this information later. You will need to add several additional references to your project for IL hooking to work: *<code>Mono.Cecil.dll</code> *<code>Mono.Cecil.Mdb.dll</code> *<code>Mono.Cecil.Pdb.dll</code> *<code>Mono.Cecil.Rocks.dll</code> *<code>MonoMod.Common.dll</code> *<code>MonoMod.RuntimeDetour.dll</code> *<code>MonoMod.Utils.dll</code> These are normally in <code>Steam\steamapps\common\Rain World\RainWorld_Data\Managed</code> (although it is again recommended to copy them somewhere else first). This guide is intended to be self-sufficient, but see also [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ Risk of Thunder's guide to IL hooking] for another perspective and more examples. A list of all IL instruction OpCodes and what they do can be found on [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields Microsoft's documentation page]. This is not required reading, but it will be a handy reference. Everything in this guide is tested with Visual Studio 2022 17.7.0, .NET Framework 4.8.04084, and Rain World 1.9.07b. Newer versions could very well break something. ==Overview== Like standard event hooking, IL hooking targets a specific method in Rain World's assembly. There are a few key differences: *A standard event hook receives references to the original method <code>orig</code> and every argument that it would have received (including <code>this</code> if non-static, which the hook receives as <code>self</code> by default). An IL hook receives only an <code>ILContext</code> which is used to navigate the method's IL instructions. *The code you write in a standard event hook is run every time the game calls the hooked method (assuming no other mods hook that method and forgo the <code>orig</code> call). In an IL hook, the code you write is run only once when the mod is initialized, but the effect of this code is to essentially modify the original method directly. *A standard event hook can essentially only cause changes at the beginning or end of an existing method. An IL hook can cause changes inside a method. A mod with an IL hook is still a BepInPlugin. [[BepInPlugins#Testing your code|Building it]], creating a [[Downpour Reference/BepInEx Files|mod directory]], and [[Downpour Reference/Mod Directories|including other files]] is still the same process. ==Procedure== As an example, we're going to hook <code>Leech.Attached</code> to prevent Jungle Leeches from draining Slugcat's food. As the relevant code is in the middle of the method, a standard event hook won't work (at least not easily). ===Step 1: Create an IL hook=== IL hooks are created similarly to standard event hooks. First, we must import a couple of things (in addition to what you would import for standard event hooks): <syntaxhighlight lang="csharp"> using Mono.Cecil.Cil; using MonoMod.Cil; </syntaxhighlight> Next, you can auto-generate the hooking method just as you would with a standard event hook. Pressing TAB after <code>+=</code> will create the hooking method automatically. <syntaxhighlight lang="csharp"> private void OnEnable() { IL.Leech.Attached += Leech_Attached; } private void Leech_Attached(ILContext il) { throw new NotImplementedException(); } </syntaxhighlight> You will also need to instantiate the cursor: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); } </syntaxhighlight> ===Step 2: Determine what to modify=== Before we can proceed, we need to know how to actually modify the method to get the effect we want. In <code>Leech.Attached</code>, the method checks whether the Leech in question is a Jungle Leech, then whether the creature it is attached to is a <code>Player</code> (Slugcat): <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> Ultimately, we want the method to ''not'' check whether the creature is a <code>Player</code> and just skip the entire following block of code, while is responsible for the food drain. Viewing the IL for this method reveals the following: <pre> 270 02FC ldarg.0 271 02FD ldfld bool Leech::jungleLeech 272 0302 brfalse 414 (050D) ldarg.0 273 0307 ldloc.0 274 0308 callvirt instance class PhysicalObject BodyChunk::get_owner() 275 030D isinst Player 276 0312 brfalse 340 (03F5) ldloc.0 </pre> Each row is an ''instruction''. The first column is the ''index'' of the instruction, which will aid in discussion of where we want to make our modifications. The third column is the ''OpCode'' for that instruction, which is very generally what the instruction does. A list of all OpCodes and what they do can be found on [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields Microsoft's documentation page]. The final column is the ''operand'' for the instruction. These particular instructions mean the following: {| class="wikitable" ! Index ! OpCode ! Operand ! Meaning ! Top of stack |- | 270 | <code>ldarg.0</code> | | Put argument 0 on the evaluation stack. In a non-static class method, argument 0 is always a reference to <code>this</code>. | <code>Leech this</code> |- | 271 | <code>ldfld</code> | <code>bool Leech::jungleLeech</code> | Pop an item off the stack, access its <code>jungleLeech</code> field, and put that <code>bool</code> on the stack. | <code>bool this.jungleLeech</code> |- | 272 | <code>brfalse</code> | <code>414</code> | Pop an item off the stack. If it is false, go to the instruction at index 414. Index 414 is just after the entire <code>if (this.jungleLeech) { ... }</code> block. | irrelevant |- | 273 | <code>ldloc.0</code> | | Put local variable 0 on the stack (the first local variable defined in this method). | <code>BodyChunk bodyChunk</code> |- | 274 | <code>callvirt</code> | <code>instance class PhysicalObject BodyChunk::get_owner()</code> | Pop an item off the stack, and call its <code>get_owner</code> property getter, and put the result on the stack. | <code>PhysicalObject bodyChunk.owner</code> |- | 275 | <code>isinst</code> | <code>Player</code> | Pop an item off the stack. Put a <code>bool</code> on the stack corresponding to whether it is an instance of <code>Player</code>. | <code>bool (bodyChunk.owner is Player)</code> |- | 276 | <code>brfalse</code> | <code>340</code> | Pop an item off the stack. If it is false, go to the instruction at index 340. Index 340 is just after <code>if (bodyChunk.owner is Player & ...) { ... }</code>. | irrelevant |} Instructions 270 and 271 correspond to <code>if (this.JungleLeech)</code>, with 272 skipping the entire code block if it is false. Instructions 273 through 275 correspond to <code>if (bodyChunk.owner is Player)</code>, with 276 skipping just the code block that affects only Slugcat if it is false. While the second conditional here is compound, conditionals are broken into their individual parts and tested individually at the IL level. This is how [[w:Short-circuit evaluation|short-circuit evaluation]] is implemented: <code>(bodyChunk.owner is Player && somethingElse)</code> has no need to evaluate <code>somethingElse</code> if <code>bodyChunk.owner is Player</code> is false. We want to have the code not even bother with checking if <code>bodyChunk.owner is Player</code> and always skip the Slugcat-specific block (which is what instruction 276 does). ===Step 3: Find the instructions of interest=== While we ''could'' tell the cursor to move directly to the index of the instructions we want to modify, that won't work reliably if any other mod IL hooks this method and changes the number of instructions. Instead, the better procedure is to ''search'' for a sequence of instructions. How many instructions should be included in this sequence is subjective. Too few, and there's a chance your hook will land somewhere it shouldn't; too many, and there's a chance another hook will modify code inside what you are trying to match, and your hook matches nothing and fails. In this example, matching instructions 270 through 276 should suffice. We tell our <code>ILCursor</code> to search for a specific sequence of instructions with <code>GotoNext</code>: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); } </syntaxhighlight> This will tell the cursor to find an <code>ldarg.0</code> instruction, followed by a <code>ldfld</code> instruction with <code>jungleLeech</code> as the operand, et cetera. Crucially, it must find all seven of these instructions in order with no gaps. If successful, this will place the cursor at index 270 - the beginning of the instruction sequence we searched for. If it fails, an exception is thrown and this hook does not get applied. ===Step 4: Modify the instructions=== From earlier, we want to insert instructions to make the method skip checking whether <code>bodyChunk.owner is Player</code> and the following block. This just involves inserting an unconditional branch instruction. However, we have to tell it ''where'' to branch to, so we have one extra step of grabbing a reference to the instruction we want to branch to. Because we told the cursor to look for the entire sequence of 7 instructions, we can be sure they all exist here, and we don't have to use <code>GotoNext</code> to search again. We do the following to achieve this: Jump to the instruction that will skip the food drain code (276). <syntaxhighlight lang="csharp">c.Index += 6;</syntaxhighlight> Grab the operand of this instruction and store it locally. The operand of a branch instruction is always another <code>ILLabel</code> which points to the instruction of interest. <syntaxhighlight lang="csharp">ILLabel inst = (ILLabel)cursor.Next.Operand;</syntaxhighlight> Jump to just before the method is checking whether <code>bodyChunk.owner is Player</code> (273). <syntaxhighlight lang="csharp">c.Index -= 3;</syntaxhighlight> Insert, or ''emit'', an instruction to branch unconditionally to the instruction we referenced earlier, skipping the food drain block. <syntaxhighlight lang="csharp">cursor.Emit(OpCodes.Br, inst);</syntaxhighlight> This new instruction exists between instructions 272 and 273 because the cursor's <code>Index</code> at the time was 273. This is what our hooking method looks like now: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Br, inst); } </syntaxhighlight> What we've effectively done is changed this piece of <code>Leech.Attached</code>: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> into this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (false && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> We've now achieved exactly what we wanted but, for the sake of example, we will now attach this behavior to the value of a <code>Configurable<bool></code> (e.g., from a Remix <code>OptionInterface</code>) to illustrate how to reference things in the current context for the IL context. ===Step 5: Use a delegate to access the current context from the IL context=== We'll assume that you have already set up a <code>Configurable<bool></code> and an <code>OptionInterface</code> to allow toggling it, and that it is stored in the static field <code>Options.foodDrainToggle</code>. Although it would be possible to reference <code>Options.foodDrainToggle</code> with some specific sequence of instructions, we can give the <code>ILCursor</code> a ''delegate'' that we write in the current context instead, and it will store that delegate to use again in the IL context when the method is actually run. In this case, it would look like: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); </syntaxhighlight> The type argument <code>Func<bool></code> indicates that the delegate takes no arguments (and thus removes nothing from the evaluation stack), but returns a boolean (which is then put on the stack). This needs to be placed just before the branch instruction we inserted earlier, which also needs to be changed to a conditional branch (<code>brfalse</code>) so that it actually checks the boolean we just put on the stack. Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> Note that when we emit, the cursor also moves forward, so we don't have to bump up the <code>Index</code> before inserting the next instruction. It is worth emphasizing that if any instruction we insert (including delegates) puts something on the evaluation stack, there ''must'' be an instruction that removes it from the stack (which, in this case, <code>brfalse</code> does), lest we leave the stack [[#Stack balance|unbalanced]] and cause the hook to fail. The equivalent C# code now looks like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> ===Step 6: Use a delegate to access the IL context from the current context=== We can put just about anything we want into the delegate. If we wanted to have Slugcat be [https://rainworld.miraheze.org/wiki/User:Alphappy/Live/Slowing slowed] while a Jungle Leech is attached, we could change our delegate to take in the <code>BodyChunk</code> that the original method already stored as a local: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); </syntaxhighlight> In contrast to earlier, this delegate takes a <code>BodyChunk</code> as input, which we must put on the stack before calling this delegate. Fortunately, because this <code>BodyChunk</code> is stored as a local already where our instructions are being inserted, that is very simple: <syntaxhighlight lang="csharp"> cursor.Emit(OpCodes.Ldloc, 0); </syntaxhighlight> Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Ldloc, 0); cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> The equivalent C# code now looks something like like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> Worth noting that, to achieve this slowing, we could have instead inserted a delegate after the instructions corresponding to <code>bodyChunk.owner is Player</code> instead so we don't have to make that check in our delegate. In that regard, what we've done here is inefficient, but it nonetheless demonstrates how to use something currently on the evaluation stack (that is, in the IL context) in the current context. ===Step 7: View the modified IL for debugging=== If you add <code>Debug.Log(il.ToString());</code> to the end of your hook, it will print the modified method. You will notice that this puts hundreds of lines in the log - thousands for longer methods. As such, it is best to not print this unless you are debugging. Assuming you did all of the above, you should see the following in the middle of the printout: <pre> IL_02fc: ldarg.0 IL_02fd: ldfld System.Boolean Leech::jungleLeech IL_0302: brfalse IL_050d IL_0000: ldloc V_0 IL_0000: ldc.i4 0 IL_0000: call T MonoMod.Cil.RuntimeILReferenceBag/InnerBag`1<System.Func`2<BodyChunk,System.Boolean>>::Get(System.Int32) IL_0000: call TResult MonoMod.Cil.RuntimeILReferenceBag/FastDelegateInvokers::Invoke<BodyChunk,System.Boolean>(T1,MonoMod.Cil.RuntimeILReferenceBag/FastDelegateInvokers/Func`2<T1,TResult>) IL_0000: brfalse IL_03f5 IL_0307: ldloc.0 IL_0308: callvirt PhysicalObject BodyChunk::get_owner() IL_030d: isinst Player IL_0312: brfalse IL_03f5 </pre> This shows ''offsets'' and not indices as dnSpy did. They are not sequential and not unique for our added IL, but they still allow us to make sure our hook is doing what we intended - for instance, we can see the <code>ldloc</code> and the <code>brfalse</code> we explicitly added with <code>Emit</code>. We also see three instructions that MonoMod added to call our delegate. They look messy because of how type arguments must be passed around, but all they do is *put an identifier for our delegate on the stack; *call a method to retrieve the delegate; and *call a method to invoke the delegate. For completeness, here's what these five new instructions mean: {| class="wikitable" ! OpCode ! Operand ! Meaning ! Top of stack |- | <code>ldloc</code> | <code>V_0</code> | Put local variable 0 on the stack (the first local variable defined in this method). | <code>BodyChunk bodyChunk</code> |- | <code>ldc.i4</code> | <code>0</code> | Put the integer 0 on the stack. | <code>int 0</code><br><code>BodyChunk bodyChunk</code> |- | <code>call</code> | <code>T ...InnerBag<Func<BodyChunk, bool>>::Get(...)</code> | Call MonoMod's <code>InnerBag.Get</code>. Because this takes one input, this also pops one item off the stack.<br> When our hooking method ran, MonoMod gave our delegate an identifier of <code>0</code>.<br> <code>InnerBag</code>, when given that identifier, will return our delegate.<br> Put the resulting <code>Func<BodyChunk, bool></code>, which is our delegate, on the stack. | <code>Func<BodyChunk, bool> delegate</code><br><code>BodyChunk bodyChunk</code> |- | <code>call</code> | <code>TResult ...FastDelegateInvokers::Invoke<BodyChunk, bool>(...)</code> | Call MonoMod's <code>FastDelegateInvokers.Invoke</code>. This will pop a number of items off the stack equal to the number of arguments to the delegate plus one.<br> In our case, it will take two arguments, which are expected to be the delegate and a <code>BodyChunk</code>.<br> MonoMod will then ''invoke'' our delegate, passing the <code>BodyChunk</code> as the sole argument.<br> Put the resulting <code>bool</code> (the <code>TResult</code> of our delegate) on the stack. | <code>bool delegate(BodyChunk bodyChunk)</code> |- | <code>brfalse</code> | <code>IL_03f5</code> | Pop an item off the stack. If it is false, go to the instruction at offset 03f5. Offset 03f5 is just after <code>if (bodyChunk.owner is Player & ...) { ... }</code>. | irrelevant |} Note that the five instructions we've added collectively push to and pop from the stack the same number of times (four, in this case). This is necessary for [[#Stack balance|stack balance]]. ==Notes== ===Stack balance=== If you get the exception <code>System.InvalidProgramException: Invalid IL code in ...: ret</code>, you've left the stack unbalanced. The number of objects on the stack before and after a method executes must be equal. If the stack is ''unbalanced'' - that is, more things are placed on the stack than are removed for a given method, or vice versa - the IL hook will fail. It is therefore important to understand [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields how each OpCode interacts with the stack]. Most instructions pop one object, push one object, or both - but some instructions may pop or push more than one object depending on their operand. ===Failure to match=== If you get the exception <code>System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.</code>, your cursor failed to find the instructions requested in a <code>Goto</code>. Most likely, it means that you've just specified one of your <code>Match</code>es incorrectly. This can also happen if you try to match a block of instructions that another IL hook modifies before yours. This is an unlikely circumstance, but becomes more likely as the number of instructions to match increases. ===Find=== <code>ILCursor</code> offers <code>FindNext</code> and <code>FindPrev</code> as an alternative to the <code>Goto</code> methods. While <code>Goto</code> requires no gaps in the sequence of requested instructions, <code>Find</code> allows any gaps, as long as at finds the instructions in the requested order. For most hooks you write, you will ''not'' want to use <code>Find</code> methods without very carefully considering how specific your searched instructions are. For instance, if you try to <code>Find</code> the instructions associated with putting <code>this.abstractCreature</code> on the stack - which involves <code>ldarg.0</code> as the first instruction - the cursor will land on the first time that <code>this</code> is put on the stack for any reason, so long as the remaining <code>ldfld</code> instruction associated with <code>this.abstractCreature</code> is ''somewhere'' further along in the method. Of course, if <code>this.abstractCreature</code> ''happens'' to be the first time <code>this</code> is put on the stack, it will still work. ===TryGoto and TryFind=== <code>ILCursor</code> offers <code>Try</code> versions of <code>Goto</code> and <code>Find</code> methods which will not raise an exception if they can't find the instructions you requested. For most hooks you write, you will ''not'' want to use the <code>Try</code> versions (in general, silent exception suppression is a bad thing). The cursor will simply not move if it can't find what you requested, meaning your next commands to inject new instructions will likely fail or cause unintended behavior since they are not where you intended them to be. ===Matching=== It is always possible to match an instruction using just <code>Match(OpCode)</code>. This will disregard to operand completely. For some instructions, it is often easier to just not bother trying to match the operand. This is especially true of branches, which require a reference to the instruction being branched to in order to be robust. You should use the more specific Match methods whenever possible, since many sequences of instructions are fairly common when operands are ignored (in our example, <code>ldarg.0</code> <code>ldfld</code> <code>brfalse</code> is a ''very'' common sequence). {| class="wikitable mw-collapsible" !colspan="3"|Examples of how to match common instructions |- !Instruction as displayed by dnSpy !Matching method !Comment |- |<code>brfalse 414</code> |<code>MatchBrfalse(instruction)</code> |To match this way, you need a reference to the instruction in the operand. It's usually sufficient to just <code>Match</code> the OpCode instead. |- |<code>call float32 [UnityEngine.CoreModule]UnityEngine.Mathf::InverseLerp(float32, float32, float32)</code> |<code>MatchCall<Mathf>("InverseLerp")</code> |Assuming that you are <code>using UnityEngine</code>. |- |<code>callvirt instance class PhysicalObject BodyChunk::get_owner()</code> |<code>MatchCallvirt<BodyChunk>("get_owner")</code> |The type information - <code>instance class PhysicalObject</code> - can be ignored. |- |<code>callvirt instance valuetype Room/Tile/TerrainType Room/Tile::get_Terrain()</code> |<code>MatchCallvirt<Room.Tile>("get_Terrain")</code> | |- |<code>isinst Player</code> |<code>MatchIsinst<Player>()</code> | |- |<code>ldarg.0</code> |<code>MatchLdarg(0)</code> | |- |<code>ldc.i4.1</code> |<code>MatchLdcI4(1)</code> | |- |<code>ldfld bool Leech::jungleLeech</code> |<code>MatchLdfld<Leech>("jungleLeech")</code> | |} ca36393031335fbcc7ccc6fee36fe012b0274b7c 562 561 2023-10-08T21:28:33Z Alphappy 121 /* Matching */ typo; make table collapsed by default wikitext text/x-wiki '''IL hooking''', or '''intermediate-language hooking''', is an alternative to standard event hooking that allows for injection of arbitrary instructions within a method. ==Prerequisites== It is assumed that you fully understand how to use a standard event hook (<code>On</code>) as described at [[BepInPlugins]]. Additionally, it will be helpful to understand the concept of an [[w:Stack (abstract data type)|evaluation stack]], which is how objects are stored at the intermediate level. [[w:High-level programming language|High-level programming languages]] like C# abstract away the evaluation stack and allow for the more human-friendly use of named variables. This will be a little more complicated in IL - objects can only be ''pushed'' to the top of the stack or ''popped'' off the top of the stack; it is not possible to access anywhere else in the stack. It is highly recommended to have a convenient way to view the IL instructions of Rain World's code. dnSpy can do this - right-click a line of code, and select ''Edit IL Instructions...'' We will cover how to interpret this information later. You will need to add several additional references to your project for IL hooking to work: *<code>Mono.Cecil.dll</code> *<code>Mono.Cecil.Mdb.dll</code> *<code>Mono.Cecil.Pdb.dll</code> *<code>Mono.Cecil.Rocks.dll</code> *<code>MonoMod.Common.dll</code> *<code>MonoMod.RuntimeDetour.dll</code> *<code>MonoMod.Utils.dll</code> These are normally in <code>Steam\steamapps\common\Rain World\RainWorld_Data\Managed</code> (although it is again recommended to copy them somewhere else first). This guide is intended to be self-sufficient, but see also [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ Risk of Thunder's guide to IL hooking] for another perspective and more examples. A list of all IL instruction OpCodes and what they do can be found on [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields Microsoft's documentation page]. This is not required reading, but it will be a handy reference. Everything in this guide is tested with Visual Studio 2022 17.7.0, .NET Framework 4.8.04084, and Rain World 1.9.07b. Newer versions could very well break something. ==Overview== Like standard event hooking, IL hooking targets a specific method in Rain World's assembly. There are a few key differences: *A standard event hook receives references to the original method <code>orig</code> and every argument that it would have received (including <code>this</code> if non-static, which the hook receives as <code>self</code> by default). An IL hook receives only an <code>ILContext</code> which is used to navigate the method's IL instructions. *The code you write in a standard event hook is run every time the game calls the hooked method (assuming no other mods hook that method and forgo the <code>orig</code> call). In an IL hook, the code you write is run only once when the mod is initialized, but the effect of this code is to essentially modify the original method directly. *A standard event hook can essentially only cause changes at the beginning or end of an existing method. An IL hook can cause changes inside a method. A mod with an IL hook is still a BepInPlugin. [[BepInPlugins#Testing your code|Building it]], creating a [[Downpour Reference/BepInEx Files|mod directory]], and [[Downpour Reference/Mod Directories|including other files]] is still the same process. ==Procedure== As an example, we're going to hook <code>Leech.Attached</code> to prevent Jungle Leeches from draining Slugcat's food. As the relevant code is in the middle of the method, a standard event hook won't work (at least not easily). ===Step 1: Create an IL hook=== IL hooks are created similarly to standard event hooks. First, we must import a couple of things (in addition to what you would import for standard event hooks): <syntaxhighlight lang="csharp"> using Mono.Cecil.Cil; using MonoMod.Cil; </syntaxhighlight> Next, you can auto-generate the hooking method just as you would with a standard event hook. Pressing TAB after <code>+=</code> will create the hooking method automatically. <syntaxhighlight lang="csharp"> private void OnEnable() { IL.Leech.Attached += Leech_Attached; } private void Leech_Attached(ILContext il) { throw new NotImplementedException(); } </syntaxhighlight> You will also need to instantiate the cursor: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); } </syntaxhighlight> ===Step 2: Determine what to modify=== Before we can proceed, we need to know how to actually modify the method to get the effect we want. In <code>Leech.Attached</code>, the method checks whether the Leech in question is a Jungle Leech, then whether the creature it is attached to is a <code>Player</code> (Slugcat): <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> Ultimately, we want the method to ''not'' check whether the creature is a <code>Player</code> and just skip the entire following block of code, while is responsible for the food drain. Viewing the IL for this method reveals the following: <pre> 270 02FC ldarg.0 271 02FD ldfld bool Leech::jungleLeech 272 0302 brfalse 414 (050D) ldarg.0 273 0307 ldloc.0 274 0308 callvirt instance class PhysicalObject BodyChunk::get_owner() 275 030D isinst Player 276 0312 brfalse 340 (03F5) ldloc.0 </pre> Each row is an ''instruction''. The first column is the ''index'' of the instruction, which will aid in discussion of where we want to make our modifications. The third column is the ''OpCode'' for that instruction, which is very generally what the instruction does. A list of all OpCodes and what they do can be found on [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields Microsoft's documentation page]. The final column is the ''operand'' for the instruction. These particular instructions mean the following: {| class="wikitable" ! Index ! OpCode ! Operand ! Meaning ! Top of stack |- | 270 | <code>ldarg.0</code> | | Put argument 0 on the evaluation stack. In a non-static class method, argument 0 is always a reference to <code>this</code>. | <code>Leech this</code> |- | 271 | <code>ldfld</code> | <code>bool Leech::jungleLeech</code> | Pop an item off the stack, access its <code>jungleLeech</code> field, and put that <code>bool</code> on the stack. | <code>bool this.jungleLeech</code> |- | 272 | <code>brfalse</code> | <code>414</code> | Pop an item off the stack. If it is false, go to the instruction at index 414. Index 414 is just after the entire <code>if (this.jungleLeech) { ... }</code> block. | irrelevant |- | 273 | <code>ldloc.0</code> | | Put local variable 0 on the stack (the first local variable defined in this method). | <code>BodyChunk bodyChunk</code> |- | 274 | <code>callvirt</code> | <code>instance class PhysicalObject BodyChunk::get_owner()</code> | Pop an item off the stack, and call its <code>get_owner</code> property getter, and put the result on the stack. | <code>PhysicalObject bodyChunk.owner</code> |- | 275 | <code>isinst</code> | <code>Player</code> | Pop an item off the stack. Put a <code>bool</code> on the stack corresponding to whether it is an instance of <code>Player</code>. | <code>bool (bodyChunk.owner is Player)</code> |- | 276 | <code>brfalse</code> | <code>340</code> | Pop an item off the stack. If it is false, go to the instruction at index 340. Index 340 is just after <code>if (bodyChunk.owner is Player & ...) { ... }</code>. | irrelevant |} Instructions 270 and 271 correspond to <code>if (this.JungleLeech)</code>, with 272 skipping the entire code block if it is false. Instructions 273 through 275 correspond to <code>if (bodyChunk.owner is Player)</code>, with 276 skipping just the code block that affects only Slugcat if it is false. While the second conditional here is compound, conditionals are broken into their individual parts and tested individually at the IL level. This is how [[w:Short-circuit evaluation|short-circuit evaluation]] is implemented: <code>(bodyChunk.owner is Player && somethingElse)</code> has no need to evaluate <code>somethingElse</code> if <code>bodyChunk.owner is Player</code> is false. We want to have the code not even bother with checking if <code>bodyChunk.owner is Player</code> and always skip the Slugcat-specific block (which is what instruction 276 does). ===Step 3: Find the instructions of interest=== While we ''could'' tell the cursor to move directly to the index of the instructions we want to modify, that won't work reliably if any other mod IL hooks this method and changes the number of instructions. Instead, the better procedure is to ''search'' for a sequence of instructions. How many instructions should be included in this sequence is subjective. Too few, and there's a chance your hook will land somewhere it shouldn't; too many, and there's a chance another hook will modify code inside what you are trying to match, and your hook matches nothing and fails. In this example, matching instructions 270 through 276 should suffice. We tell our <code>ILCursor</code> to search for a specific sequence of instructions with <code>GotoNext</code>: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); } </syntaxhighlight> This will tell the cursor to find an <code>ldarg.0</code> instruction, followed by a <code>ldfld</code> instruction with <code>jungleLeech</code> as the operand, et cetera. Crucially, it must find all seven of these instructions in order with no gaps. If successful, this will place the cursor at index 270 - the beginning of the instruction sequence we searched for. If it fails, an exception is thrown and this hook does not get applied. ===Step 4: Modify the instructions=== From earlier, we want to insert instructions to make the method skip checking whether <code>bodyChunk.owner is Player</code> and the following block. This just involves inserting an unconditional branch instruction. However, we have to tell it ''where'' to branch to, so we have one extra step of grabbing a reference to the instruction we want to branch to. Because we told the cursor to look for the entire sequence of 7 instructions, we can be sure they all exist here, and we don't have to use <code>GotoNext</code> to search again. We do the following to achieve this: Jump to the instruction that will skip the food drain code (276). <syntaxhighlight lang="csharp">c.Index += 6;</syntaxhighlight> Grab the operand of this instruction and store it locally. The operand of a branch instruction is always another <code>ILLabel</code> which points to the instruction of interest. <syntaxhighlight lang="csharp">ILLabel inst = (ILLabel)cursor.Next.Operand;</syntaxhighlight> Jump to just before the method is checking whether <code>bodyChunk.owner is Player</code> (273). <syntaxhighlight lang="csharp">c.Index -= 3;</syntaxhighlight> Insert, or ''emit'', an instruction to branch unconditionally to the instruction we referenced earlier, skipping the food drain block. <syntaxhighlight lang="csharp">cursor.Emit(OpCodes.Br, inst);</syntaxhighlight> This new instruction exists between instructions 272 and 273 because the cursor's <code>Index</code> at the time was 273. This is what our hooking method looks like now: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Br, inst); } </syntaxhighlight> What we've effectively done is changed this piece of <code>Leech.Attached</code>: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> into this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (false && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> We've now achieved exactly what we wanted but, for the sake of example, we will now attach this behavior to the value of a <code>Configurable<bool></code> (e.g., from a Remix <code>OptionInterface</code>) to illustrate how to reference things in the current context for the IL context. ===Step 5: Use a delegate to access the current context from the IL context=== We'll assume that you have already set up a <code>Configurable<bool></code> and an <code>OptionInterface</code> to allow toggling it, and that it is stored in the static field <code>Options.foodDrainToggle</code>. Although it would be possible to reference <code>Options.foodDrainToggle</code> with some specific sequence of instructions, we can give the <code>ILCursor</code> a ''delegate'' that we write in the current context instead, and it will store that delegate to use again in the IL context when the method is actually run. In this case, it would look like: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); </syntaxhighlight> The type argument <code>Func<bool></code> indicates that the delegate takes no arguments (and thus removes nothing from the evaluation stack), but returns a boolean (which is then put on the stack). This needs to be placed just before the branch instruction we inserted earlier, which also needs to be changed to a conditional branch (<code>brfalse</code>) so that it actually checks the boolean we just put on the stack. Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> Note that when we emit, the cursor also moves forward, so we don't have to bump up the <code>Index</code> before inserting the next instruction. It is worth emphasizing that if any instruction we insert (including delegates) puts something on the evaluation stack, there ''must'' be an instruction that removes it from the stack (which, in this case, <code>brfalse</code> does), lest we leave the stack [[#Stack balance|unbalanced]] and cause the hook to fail. The equivalent C# code now looks like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> ===Step 6: Use a delegate to access the IL context from the current context=== We can put just about anything we want into the delegate. If we wanted to have Slugcat be [https://rainworld.miraheze.org/wiki/User:Alphappy/Live/Slowing slowed] while a Jungle Leech is attached, we could change our delegate to take in the <code>BodyChunk</code> that the original method already stored as a local: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); </syntaxhighlight> In contrast to earlier, this delegate takes a <code>BodyChunk</code> as input, which we must put on the stack before calling this delegate. Fortunately, because this <code>BodyChunk</code> is stored as a local already where our instructions are being inserted, that is very simple: <syntaxhighlight lang="csharp"> cursor.Emit(OpCodes.Ldloc, 0); </syntaxhighlight> Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Ldloc, 0); cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> The equivalent C# code now looks something like like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> Worth noting that, to achieve this slowing, we could have instead inserted a delegate after the instructions corresponding to <code>bodyChunk.owner is Player</code> instead so we don't have to make that check in our delegate. In that regard, what we've done here is inefficient, but it nonetheless demonstrates how to use something currently on the evaluation stack (that is, in the IL context) in the current context. ===Step 7: View the modified IL for debugging=== If you add <code>Debug.Log(il.ToString());</code> to the end of your hook, it will print the modified method. You will notice that this puts hundreds of lines in the log - thousands for longer methods. As such, it is best to not print this unless you are debugging. Assuming you did all of the above, you should see the following in the middle of the printout: <pre> IL_02fc: ldarg.0 IL_02fd: ldfld System.Boolean Leech::jungleLeech IL_0302: brfalse IL_050d IL_0000: ldloc V_0 IL_0000: ldc.i4 0 IL_0000: call T MonoMod.Cil.RuntimeILReferenceBag/InnerBag`1<System.Func`2<BodyChunk,System.Boolean>>::Get(System.Int32) IL_0000: call TResult MonoMod.Cil.RuntimeILReferenceBag/FastDelegateInvokers::Invoke<BodyChunk,System.Boolean>(T1,MonoMod.Cil.RuntimeILReferenceBag/FastDelegateInvokers/Func`2<T1,TResult>) IL_0000: brfalse IL_03f5 IL_0307: ldloc.0 IL_0308: callvirt PhysicalObject BodyChunk::get_owner() IL_030d: isinst Player IL_0312: brfalse IL_03f5 </pre> This shows ''offsets'' and not indices as dnSpy did. They are not sequential and not unique for our added IL, but they still allow us to make sure our hook is doing what we intended - for instance, we can see the <code>ldloc</code> and the <code>brfalse</code> we explicitly added with <code>Emit</code>. We also see three instructions that MonoMod added to call our delegate. They look messy because of how type arguments must be passed around, but all they do is *put an identifier for our delegate on the stack; *call a method to retrieve the delegate; and *call a method to invoke the delegate. For completeness, here's what these five new instructions mean: {| class="wikitable" ! OpCode ! Operand ! Meaning ! Top of stack |- | <code>ldloc</code> | <code>V_0</code> | Put local variable 0 on the stack (the first local variable defined in this method). | <code>BodyChunk bodyChunk</code> |- | <code>ldc.i4</code> | <code>0</code> | Put the integer 0 on the stack. | <code>int 0</code><br><code>BodyChunk bodyChunk</code> |- | <code>call</code> | <code>T ...InnerBag<Func<BodyChunk, bool>>::Get(...)</code> | Call MonoMod's <code>InnerBag.Get</code>. Because this takes one input, this also pops one item off the stack.<br> When our hooking method ran, MonoMod gave our delegate an identifier of <code>0</code>.<br> <code>InnerBag</code>, when given that identifier, will return our delegate.<br> Put the resulting <code>Func<BodyChunk, bool></code>, which is our delegate, on the stack. | <code>Func<BodyChunk, bool> delegate</code><br><code>BodyChunk bodyChunk</code> |- | <code>call</code> | <code>TResult ...FastDelegateInvokers::Invoke<BodyChunk, bool>(...)</code> | Call MonoMod's <code>FastDelegateInvokers.Invoke</code>. This will pop a number of items off the stack equal to the number of arguments to the delegate plus one.<br> In our case, it will take two arguments, which are expected to be the delegate and a <code>BodyChunk</code>.<br> MonoMod will then ''invoke'' our delegate, passing the <code>BodyChunk</code> as the sole argument.<br> Put the resulting <code>bool</code> (the <code>TResult</code> of our delegate) on the stack. | <code>bool delegate(BodyChunk bodyChunk)</code> |- | <code>brfalse</code> | <code>IL_03f5</code> | Pop an item off the stack. If it is false, go to the instruction at offset 03f5. Offset 03f5 is just after <code>if (bodyChunk.owner is Player & ...) { ... }</code>. | irrelevant |} Note that the five instructions we've added collectively push to and pop from the stack the same number of times (four, in this case). This is necessary for [[#Stack balance|stack balance]]. ==Notes== ===Stack balance=== If you get the exception <code>System.InvalidProgramException: Invalid IL code in ...: ret</code>, you've left the stack unbalanced. The number of objects on the stack before and after a method executes must be equal. If the stack is ''unbalanced'' - that is, more things are placed on the stack than are removed for a given method, or vice versa - the IL hook will fail. It is therefore important to understand [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields how each OpCode interacts with the stack]. Most instructions pop one object, push one object, or both - but some instructions may pop or push more than one object depending on their operand. ===Failure to match=== If you get the exception <code>System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.</code>, your cursor failed to find the instructions requested in a <code>Goto</code>. Most likely, it means that you've just specified one of your <code>Match</code>es incorrectly. This can also happen if you try to match a block of instructions that another IL hook modifies before yours. This is an unlikely circumstance, but becomes more likely as the number of instructions to match increases. ===Find=== <code>ILCursor</code> offers <code>FindNext</code> and <code>FindPrev</code> as an alternative to the <code>Goto</code> methods. While <code>Goto</code> requires no gaps in the sequence of requested instructions, <code>Find</code> allows any gaps, as long as at finds the instructions in the requested order. For most hooks you write, you will ''not'' want to use <code>Find</code> methods without very carefully considering how specific your searched instructions are. For instance, if you try to <code>Find</code> the instructions associated with putting <code>this.abstractCreature</code> on the stack - which involves <code>ldarg.0</code> as the first instruction - the cursor will land on the first time that <code>this</code> is put on the stack for any reason, so long as the remaining <code>ldfld</code> instruction associated with <code>this.abstractCreature</code> is ''somewhere'' further along in the method. Of course, if <code>this.abstractCreature</code> ''happens'' to be the first time <code>this</code> is put on the stack, it will still work. ===TryGoto and TryFind=== <code>ILCursor</code> offers <code>Try</code> versions of <code>Goto</code> and <code>Find</code> methods which will not raise an exception if they can't find the instructions you requested. For most hooks you write, you will ''not'' want to use the <code>Try</code> versions (in general, silent exception suppression is a bad thing). The cursor will simply not move if it can't find what you requested, meaning your next commands to inject new instructions will likely fail or cause unintended behavior since they are not where you intended them to be. ===Matching=== It is always possible to match an instruction using just <code>Match(OpCode)</code>. This will disregard the operand completely. For some instructions, it is often easier to just not bother trying to match the operand. This is especially true of branches, which require a reference to the instruction being branched to in order to be robust. You should use the more specific Match methods whenever possible, since many sequences of instructions are fairly common when operands are ignored (in our example, <code>ldarg.0</code> <code>ldfld</code> <code>brfalse</code> is a ''very'' common sequence). {| class="wikitable mw-collapsible mw-collapsed sortable" !colspan="3"|Examples of how to match common instructions |- !Instruction as displayed by dnSpy !Matching method !Comment |- |<code>brfalse 414</code> |<code>MatchBrfalse(instruction)</code> |To match this way, you need a reference to the instruction in the operand. It's usually sufficient to just <code>Match</code> the OpCode instead. |- |<code>call float32 [UnityEngine.CoreModule]UnityEngine.Mathf::InverseLerp(float32, float32, float32)</code> |<code>MatchCall<Mathf>("InverseLerp")</code> |Assuming that you are <code>using UnityEngine</code>. |- |<code>callvirt instance class PhysicalObject BodyChunk::get_owner()</code> |<code>MatchCallvirt<BodyChunk>("get_owner")</code> |The type information - <code>instance class PhysicalObject</code> - can be ignored. |- |<code>callvirt instance valuetype Room/Tile/TerrainType Room/Tile::get_Terrain()</code> |<code>MatchCallvirt<Room.Tile>("get_Terrain")</code> | |- |<code>isinst Player</code> |<code>MatchIsinst<Player>()</code> | |- |<code>ldarg.0</code> |<code>MatchLdarg(0)</code> | |- |<code>ldc.i4.1</code> |<code>MatchLdcI4(1)</code> | |- |<code>ldfld bool Leech::jungleLeech</code> |<code>MatchLdfld<Leech>("jungleLeech")</code> | |} d53f70f6ffe7c4b33817f9c578e1bdbe45cf99f6 563 562 2023-10-08T21:32:26Z Alphappy 121 /* Step 3: Find the instructions of interest */ link to the notes wikitext text/x-wiki '''IL hooking''', or '''intermediate-language hooking''', is an alternative to standard event hooking that allows for injection of arbitrary instructions within a method. ==Prerequisites== It is assumed that you fully understand how to use a standard event hook (<code>On</code>) as described at [[BepInPlugins]]. Additionally, it will be helpful to understand the concept of an [[w:Stack (abstract data type)|evaluation stack]], which is how objects are stored at the intermediate level. [[w:High-level programming language|High-level programming languages]] like C# abstract away the evaluation stack and allow for the more human-friendly use of named variables. This will be a little more complicated in IL - objects can only be ''pushed'' to the top of the stack or ''popped'' off the top of the stack; it is not possible to access anywhere else in the stack. It is highly recommended to have a convenient way to view the IL instructions of Rain World's code. dnSpy can do this - right-click a line of code, and select ''Edit IL Instructions...'' We will cover how to interpret this information later. You will need to add several additional references to your project for IL hooking to work: *<code>Mono.Cecil.dll</code> *<code>Mono.Cecil.Mdb.dll</code> *<code>Mono.Cecil.Pdb.dll</code> *<code>Mono.Cecil.Rocks.dll</code> *<code>MonoMod.Common.dll</code> *<code>MonoMod.RuntimeDetour.dll</code> *<code>MonoMod.Utils.dll</code> These are normally in <code>Steam\steamapps\common\Rain World\RainWorld_Data\Managed</code> (although it is again recommended to copy them somewhere else first). This guide is intended to be self-sufficient, but see also [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ Risk of Thunder's guide to IL hooking] for another perspective and more examples. A list of all IL instruction OpCodes and what they do can be found on [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields Microsoft's documentation page]. This is not required reading, but it will be a handy reference. Everything in this guide is tested with Visual Studio 2022 17.7.0, .NET Framework 4.8.04084, and Rain World 1.9.07b. Newer versions could very well break something. ==Overview== Like standard event hooking, IL hooking targets a specific method in Rain World's assembly. There are a few key differences: *A standard event hook receives references to the original method <code>orig</code> and every argument that it would have received (including <code>this</code> if non-static, which the hook receives as <code>self</code> by default). An IL hook receives only an <code>ILContext</code> which is used to navigate the method's IL instructions. *The code you write in a standard event hook is run every time the game calls the hooked method (assuming no other mods hook that method and forgo the <code>orig</code> call). In an IL hook, the code you write is run only once when the mod is initialized, but the effect of this code is to essentially modify the original method directly. *A standard event hook can essentially only cause changes at the beginning or end of an existing method. An IL hook can cause changes inside a method. A mod with an IL hook is still a BepInPlugin. [[BepInPlugins#Testing your code|Building it]], creating a [[Downpour Reference/BepInEx Files|mod directory]], and [[Downpour Reference/Mod Directories|including other files]] is still the same process. ==Procedure== As an example, we're going to hook <code>Leech.Attached</code> to prevent Jungle Leeches from draining Slugcat's food. As the relevant code is in the middle of the method, a standard event hook won't work (at least not easily). ===Step 1: Create an IL hook=== IL hooks are created similarly to standard event hooks. First, we must import a couple of things (in addition to what you would import for standard event hooks): <syntaxhighlight lang="csharp"> using Mono.Cecil.Cil; using MonoMod.Cil; </syntaxhighlight> Next, you can auto-generate the hooking method just as you would with a standard event hook. Pressing TAB after <code>+=</code> will create the hooking method automatically. <syntaxhighlight lang="csharp"> private void OnEnable() { IL.Leech.Attached += Leech_Attached; } private void Leech_Attached(ILContext il) { throw new NotImplementedException(); } </syntaxhighlight> You will also need to instantiate the cursor: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); } </syntaxhighlight> ===Step 2: Determine what to modify=== Before we can proceed, we need to know how to actually modify the method to get the effect we want. In <code>Leech.Attached</code>, the method checks whether the Leech in question is a Jungle Leech, then whether the creature it is attached to is a <code>Player</code> (Slugcat): <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> Ultimately, we want the method to ''not'' check whether the creature is a <code>Player</code> and just skip the entire following block of code, while is responsible for the food drain. Viewing the IL for this method reveals the following: <pre> 270 02FC ldarg.0 271 02FD ldfld bool Leech::jungleLeech 272 0302 brfalse 414 (050D) ldarg.0 273 0307 ldloc.0 274 0308 callvirt instance class PhysicalObject BodyChunk::get_owner() 275 030D isinst Player 276 0312 brfalse 340 (03F5) ldloc.0 </pre> Each row is an ''instruction''. The first column is the ''index'' of the instruction, which will aid in discussion of where we want to make our modifications. The third column is the ''OpCode'' for that instruction, which is very generally what the instruction does. A list of all OpCodes and what they do can be found on [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields Microsoft's documentation page]. The final column is the ''operand'' for the instruction. These particular instructions mean the following: {| class="wikitable" ! Index ! OpCode ! Operand ! Meaning ! Top of stack |- | 270 | <code>ldarg.0</code> | | Put argument 0 on the evaluation stack. In a non-static class method, argument 0 is always a reference to <code>this</code>. | <code>Leech this</code> |- | 271 | <code>ldfld</code> | <code>bool Leech::jungleLeech</code> | Pop an item off the stack, access its <code>jungleLeech</code> field, and put that <code>bool</code> on the stack. | <code>bool this.jungleLeech</code> |- | 272 | <code>brfalse</code> | <code>414</code> | Pop an item off the stack. If it is false, go to the instruction at index 414. Index 414 is just after the entire <code>if (this.jungleLeech) { ... }</code> block. | irrelevant |- | 273 | <code>ldloc.0</code> | | Put local variable 0 on the stack (the first local variable defined in this method). | <code>BodyChunk bodyChunk</code> |- | 274 | <code>callvirt</code> | <code>instance class PhysicalObject BodyChunk::get_owner()</code> | Pop an item off the stack, and call its <code>get_owner</code> property getter, and put the result on the stack. | <code>PhysicalObject bodyChunk.owner</code> |- | 275 | <code>isinst</code> | <code>Player</code> | Pop an item off the stack. Put a <code>bool</code> on the stack corresponding to whether it is an instance of <code>Player</code>. | <code>bool (bodyChunk.owner is Player)</code> |- | 276 | <code>brfalse</code> | <code>340</code> | Pop an item off the stack. If it is false, go to the instruction at index 340. Index 340 is just after <code>if (bodyChunk.owner is Player & ...) { ... }</code>. | irrelevant |} Instructions 270 and 271 correspond to <code>if (this.JungleLeech)</code>, with 272 skipping the entire code block if it is false. Instructions 273 through 275 correspond to <code>if (bodyChunk.owner is Player)</code>, with 276 skipping just the code block that affects only Slugcat if it is false. While the second conditional here is compound, conditionals are broken into their individual parts and tested individually at the IL level. This is how [[w:Short-circuit evaluation|short-circuit evaluation]] is implemented: <code>(bodyChunk.owner is Player && somethingElse)</code> has no need to evaluate <code>somethingElse</code> if <code>bodyChunk.owner is Player</code> is false. We want to have the code not even bother with checking if <code>bodyChunk.owner is Player</code> and always skip the Slugcat-specific block (which is what instruction 276 does). ===Step 3: Find the instructions of interest=== While we ''could'' tell the cursor to move directly to the index of the instructions we want to modify, that won't work reliably if any other mod IL hooks this method and changes the number of instructions. Instead, the better procedure is to ''search'' for a sequence of instructions. How many instructions should be included in this sequence is subjective. Too few, and there's a chance your hook will land somewhere it shouldn't; too many, and there's a chance another hook will modify code inside what you are trying to match, and your hook matches nothing and fails. In this example, matching instructions 270 through 276 should suffice. We tell our <code>ILCursor</code> to search for a specific sequence of instructions with <code>GotoNext</code>: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); } </syntaxhighlight> This will tell the cursor to find an <code>ldarg.0</code> instruction, followed by a <code>ldfld</code> instruction with <code>jungleLeech</code> as the operand, et cetera. Crucially, it must find all seven of these instructions in order with no gaps. Hopefully, using the <code>Match</code> methods is fairly straightforward given their required arguments (which Visual Studio will show you). Some other examples of matching are presented [[#Matching|in the notes]]. If successful, this will place the cursor at index 270 - the beginning of the instruction sequence we searched for. If it fails, an exception is thrown and this hook does not get applied. ===Step 4: Modify the instructions=== From earlier, we want to insert instructions to make the method skip checking whether <code>bodyChunk.owner is Player</code> and the following block. This just involves inserting an unconditional branch instruction. However, we have to tell it ''where'' to branch to, so we have one extra step of grabbing a reference to the instruction we want to branch to. Because we told the cursor to look for the entire sequence of 7 instructions, we can be sure they all exist here, and we don't have to use <code>GotoNext</code> to search again. We do the following to achieve this: Jump to the instruction that will skip the food drain code (276). <syntaxhighlight lang="csharp">c.Index += 6;</syntaxhighlight> Grab the operand of this instruction and store it locally. The operand of a branch instruction is always another <code>ILLabel</code> which points to the instruction of interest. <syntaxhighlight lang="csharp">ILLabel inst = (ILLabel)cursor.Next.Operand;</syntaxhighlight> Jump to just before the method is checking whether <code>bodyChunk.owner is Player</code> (273). <syntaxhighlight lang="csharp">c.Index -= 3;</syntaxhighlight> Insert, or ''emit'', an instruction to branch unconditionally to the instruction we referenced earlier, skipping the food drain block. <syntaxhighlight lang="csharp">cursor.Emit(OpCodes.Br, inst);</syntaxhighlight> This new instruction exists between instructions 272 and 273 because the cursor's <code>Index</code> at the time was 273. This is what our hooking method looks like now: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Br, inst); } </syntaxhighlight> What we've effectively done is changed this piece of <code>Leech.Attached</code>: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> into this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (false && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> We've now achieved exactly what we wanted but, for the sake of example, we will now attach this behavior to the value of a <code>Configurable<bool></code> (e.g., from a Remix <code>OptionInterface</code>) to illustrate how to reference things in the current context for the IL context. ===Step 5: Use a delegate to access the current context from the IL context=== We'll assume that you have already set up a <code>Configurable<bool></code> and an <code>OptionInterface</code> to allow toggling it, and that it is stored in the static field <code>Options.foodDrainToggle</code>. Although it would be possible to reference <code>Options.foodDrainToggle</code> with some specific sequence of instructions, we can give the <code>ILCursor</code> a ''delegate'' that we write in the current context instead, and it will store that delegate to use again in the IL context when the method is actually run. In this case, it would look like: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); </syntaxhighlight> The type argument <code>Func<bool></code> indicates that the delegate takes no arguments (and thus removes nothing from the evaluation stack), but returns a boolean (which is then put on the stack). This needs to be placed just before the branch instruction we inserted earlier, which also needs to be changed to a conditional branch (<code>brfalse</code>) so that it actually checks the boolean we just put on the stack. Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> Note that when we emit, the cursor also moves forward, so we don't have to bump up the <code>Index</code> before inserting the next instruction. It is worth emphasizing that if any instruction we insert (including delegates) puts something on the evaluation stack, there ''must'' be an instruction that removes it from the stack (which, in this case, <code>brfalse</code> does), lest we leave the stack [[#Stack balance|unbalanced]] and cause the hook to fail. The equivalent C# code now looks like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> ===Step 6: Use a delegate to access the IL context from the current context=== We can put just about anything we want into the delegate. If we wanted to have Slugcat be [https://rainworld.miraheze.org/wiki/User:Alphappy/Live/Slowing slowed] while a Jungle Leech is attached, we could change our delegate to take in the <code>BodyChunk</code> that the original method already stored as a local: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); </syntaxhighlight> In contrast to earlier, this delegate takes a <code>BodyChunk</code> as input, which we must put on the stack before calling this delegate. Fortunately, because this <code>BodyChunk</code> is stored as a local already where our instructions are being inserted, that is very simple: <syntaxhighlight lang="csharp"> cursor.Emit(OpCodes.Ldloc, 0); </syntaxhighlight> Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Ldloc, 0); cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> The equivalent C# code now looks something like like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> Worth noting that, to achieve this slowing, we could have instead inserted a delegate after the instructions corresponding to <code>bodyChunk.owner is Player</code> instead so we don't have to make that check in our delegate. In that regard, what we've done here is inefficient, but it nonetheless demonstrates how to use something currently on the evaluation stack (that is, in the IL context) in the current context. ===Step 7: View the modified IL for debugging=== If you add <code>Debug.Log(il.ToString());</code> to the end of your hook, it will print the modified method. You will notice that this puts hundreds of lines in the log - thousands for longer methods. As such, it is best to not print this unless you are debugging. Assuming you did all of the above, you should see the following in the middle of the printout: <pre> IL_02fc: ldarg.0 IL_02fd: ldfld System.Boolean Leech::jungleLeech IL_0302: brfalse IL_050d IL_0000: ldloc V_0 IL_0000: ldc.i4 0 IL_0000: call T MonoMod.Cil.RuntimeILReferenceBag/InnerBag`1<System.Func`2<BodyChunk,System.Boolean>>::Get(System.Int32) IL_0000: call TResult MonoMod.Cil.RuntimeILReferenceBag/FastDelegateInvokers::Invoke<BodyChunk,System.Boolean>(T1,MonoMod.Cil.RuntimeILReferenceBag/FastDelegateInvokers/Func`2<T1,TResult>) IL_0000: brfalse IL_03f5 IL_0307: ldloc.0 IL_0308: callvirt PhysicalObject BodyChunk::get_owner() IL_030d: isinst Player IL_0312: brfalse IL_03f5 </pre> This shows ''offsets'' and not indices as dnSpy did. They are not sequential and not unique for our added IL, but they still allow us to make sure our hook is doing what we intended - for instance, we can see the <code>ldloc</code> and the <code>brfalse</code> we explicitly added with <code>Emit</code>. We also see three instructions that MonoMod added to call our delegate. They look messy because of how type arguments must be passed around, but all they do is *put an identifier for our delegate on the stack; *call a method to retrieve the delegate; and *call a method to invoke the delegate. For completeness, here's what these five new instructions mean: {| class="wikitable" ! OpCode ! Operand ! Meaning ! Top of stack |- | <code>ldloc</code> | <code>V_0</code> | Put local variable 0 on the stack (the first local variable defined in this method). | <code>BodyChunk bodyChunk</code> |- | <code>ldc.i4</code> | <code>0</code> | Put the integer 0 on the stack. | <code>int 0</code><br><code>BodyChunk bodyChunk</code> |- | <code>call</code> | <code>T ...InnerBag<Func<BodyChunk, bool>>::Get(...)</code> | Call MonoMod's <code>InnerBag.Get</code>. Because this takes one input, this also pops one item off the stack.<br> When our hooking method ran, MonoMod gave our delegate an identifier of <code>0</code>.<br> <code>InnerBag</code>, when given that identifier, will return our delegate.<br> Put the resulting <code>Func<BodyChunk, bool></code>, which is our delegate, on the stack. | <code>Func<BodyChunk, bool> delegate</code><br><code>BodyChunk bodyChunk</code> |- | <code>call</code> | <code>TResult ...FastDelegateInvokers::Invoke<BodyChunk, bool>(...)</code> | Call MonoMod's <code>FastDelegateInvokers.Invoke</code>. This will pop a number of items off the stack equal to the number of arguments to the delegate plus one.<br> In our case, it will take two arguments, which are expected to be the delegate and a <code>BodyChunk</code>.<br> MonoMod will then ''invoke'' our delegate, passing the <code>BodyChunk</code> as the sole argument.<br> Put the resulting <code>bool</code> (the <code>TResult</code> of our delegate) on the stack. | <code>bool delegate(BodyChunk bodyChunk)</code> |- | <code>brfalse</code> | <code>IL_03f5</code> | Pop an item off the stack. If it is false, go to the instruction at offset 03f5. Offset 03f5 is just after <code>if (bodyChunk.owner is Player & ...) { ... }</code>. | irrelevant |} Note that the five instructions we've added collectively push to and pop from the stack the same number of times (four, in this case). This is necessary for [[#Stack balance|stack balance]]. ==Notes== ===Stack balance=== If you get the exception <code>System.InvalidProgramException: Invalid IL code in ...: ret</code>, you've left the stack unbalanced. The number of objects on the stack before and after a method executes must be equal. If the stack is ''unbalanced'' - that is, more things are placed on the stack than are removed for a given method, or vice versa - the IL hook will fail. It is therefore important to understand [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields how each OpCode interacts with the stack]. Most instructions pop one object, push one object, or both - but some instructions may pop or push more than one object depending on their operand. ===Failure to match=== If you get the exception <code>System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.</code>, your cursor failed to find the instructions requested in a <code>Goto</code>. Most likely, it means that you've just specified one of your <code>Match</code>es incorrectly. This can also happen if you try to match a block of instructions that another IL hook modifies before yours. This is an unlikely circumstance, but becomes more likely as the number of instructions to match increases. ===Find=== <code>ILCursor</code> offers <code>FindNext</code> and <code>FindPrev</code> as an alternative to the <code>Goto</code> methods. While <code>Goto</code> requires no gaps in the sequence of requested instructions, <code>Find</code> allows any gaps, as long as at finds the instructions in the requested order. For most hooks you write, you will ''not'' want to use <code>Find</code> methods without very carefully considering how specific your searched instructions are. For instance, if you try to <code>Find</code> the instructions associated with putting <code>this.abstractCreature</code> on the stack - which involves <code>ldarg.0</code> as the first instruction - the cursor will land on the first time that <code>this</code> is put on the stack for any reason, so long as the remaining <code>ldfld</code> instruction associated with <code>this.abstractCreature</code> is ''somewhere'' further along in the method. Of course, if <code>this.abstractCreature</code> ''happens'' to be the first time <code>this</code> is put on the stack, it will still work. ===TryGoto and TryFind=== <code>ILCursor</code> offers <code>Try</code> versions of <code>Goto</code> and <code>Find</code> methods which will not raise an exception if they can't find the instructions you requested. For most hooks you write, you will ''not'' want to use the <code>Try</code> versions (in general, silent exception suppression is a bad thing). The cursor will simply not move if it can't find what you requested, meaning your next commands to inject new instructions will likely fail or cause unintended behavior since they are not where you intended them to be. ===Matching=== It is always possible to match an instruction using just <code>Match(OpCode)</code>. This will disregard the operand completely. For some instructions, it is often easier to just not bother trying to match the operand. This is especially true of branches, which require a reference to the instruction being branched to in order to be robust. You should use the more specific Match methods whenever possible, since many sequences of instructions are fairly common when operands are ignored (in our example, <code>ldarg.0</code> <code>ldfld</code> <code>brfalse</code> is a ''very'' common sequence). {| class="wikitable mw-collapsible mw-collapsed sortable" !colspan="3"|Examples of how to match common instructions |- !Instruction as displayed by dnSpy !Matching method !Comment |- |<code>brfalse 414</code> |<code>MatchBrfalse(instruction)</code> |To match this way, you need a reference to the instruction in the operand. It's usually sufficient to just <code>Match</code> the OpCode instead. |- |<code>call float32 [UnityEngine.CoreModule]UnityEngine.Mathf::InverseLerp(float32, float32, float32)</code> |<code>MatchCall<Mathf>("InverseLerp")</code> |Assuming that you are <code>using UnityEngine</code>. |- |<code>callvirt instance class PhysicalObject BodyChunk::get_owner()</code> |<code>MatchCallvirt<BodyChunk>("get_owner")</code> |The type information - <code>instance class PhysicalObject</code> - can be ignored. |- |<code>callvirt instance valuetype Room/Tile/TerrainType Room/Tile::get_Terrain()</code> |<code>MatchCallvirt<Room.Tile>("get_Terrain")</code> | |- |<code>isinst Player</code> |<code>MatchIsinst<Player>()</code> | |- |<code>ldarg.0</code> |<code>MatchLdarg(0)</code> | |- |<code>ldc.i4.1</code> |<code>MatchLdcI4(1)</code> | |- |<code>ldfld bool Leech::jungleLeech</code> |<code>MatchLdfld<Leech>("jungleLeech")</code> | |} c6bf8e6c6e828e9cdb42cb4b8bbac4ddecb48310 564 563 2023-10-09T21:57:46Z Alphappy 121 add pros/cons summary; reformat step 4 to take up less vertical space; rewording the delegate placement discussion; label debugging as its own thing rather than a 7th step; add note about the nonuniqueness of the C# equivalents; add note about declaring delegates wikitext text/x-wiki '''IL hooking''', or '''intermediate-language hooking''', is an alternative to standard event hooking that allows for injection of arbitrary instructions within a method. ==Prerequisites== It is assumed that you fully understand how to use a standard event hook (<code>On</code>) as described at [[BepInPlugins]]. Additionally, it will be helpful to understand the concept of an [[w:Stack (abstract data type)|evaluation stack]], which is how objects are stored at the intermediate level. [[w:High-level programming language|High-level programming languages]] like C# abstract away the evaluation stack and allow for the more human-friendly use of named variables. This will be a little more complicated in IL - objects can only be ''pushed'' to the top of the stack or ''popped'' off the top of the stack; it is not possible to access anywhere else in the stack. It is highly recommended to have a convenient way to view the IL instructions of Rain World's code. dnSpy can do this - right-click a line of code, and select ''Edit IL Instructions...'' We will cover how to interpret this information later. You will need to add several additional references to your project for IL hooking to work: *<code>Mono.Cecil.dll</code> *<code>Mono.Cecil.Mdb.dll</code> *<code>Mono.Cecil.Pdb.dll</code> *<code>Mono.Cecil.Rocks.dll</code> *<code>MonoMod.Common.dll</code> *<code>MonoMod.RuntimeDetour.dll</code> *<code>MonoMod.Utils.dll</code> These are normally in <code>Steam\steamapps\common\Rain World\RainWorld_Data\Managed</code> (although it is again recommended to copy them somewhere else first). This guide is intended to be self-sufficient, but see also [https://risk-of-thunder.github.io/R2Wiki/Mod-Creation/C%23-Programming/IL-Hooking/ Risk of Thunder's guide to IL hooking] for another perspective and more examples. A list of all IL instruction OpCodes and what they do can be found on [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields Microsoft's documentation page]. This is not required reading, but it will be a handy reference. Everything in this guide is tested with Visual Studio 2022 17.7.0, .NET Framework 4.8.04084, and Rain World 1.9.07b. Newer versions could very well break something. ==Overview== Like standard event hooking, IL hooking targets a specific method in Rain World's assembly. There are a few key differences: *A standard event hook receives references to the original method <code>orig</code> and every argument that it would have received (including <code>this</code> if non-static, which the hook receives as <code>self</code> by default). An IL hook receives only an <code>ILContext</code> which is used to navigate the method's IL instructions. *The code you write in a standard event hook is run every time the game calls the hooked method (assuming no other mods hook that method and forgo the <code>orig</code> call). In an IL hook, the code you write is run only once when the mod is initialized, but the effect of this code is to essentially modify the original method directly. *A standard event hook can essentially only cause changes at the beginning or end of an existing method. An IL hook can cause changes inside a method. A mod with an IL hook is still a BepInPlugin. [[BepInPlugins#Testing your code|Building it]], creating a [[Downpour Reference/BepInEx Files|mod directory]], and [[Downpour Reference/Mod Directories|including other files]] is still the same process. ===Advantages of IL hooking=== *IL hooking allows modifications in the middle of a method - this is the principal reason to use it over standard event hooking. *IL hooking allows access to the locals of a method. *IL hooking avoids the extra overhead of additional method calls incurred by standard event hooking, which lessens its impact on performance. *IL hooking allows for more specific targeting of desired changes. ===Disadvantages of IL hooking=== *IL hooking is more difficult to learn and perform. Many modifications are simpler and faster for you to write as standard event hooks, and the performance impact often does not matter for simpler mods. *IL hooking is more prone to incompatibility (with other IL hooks on the same method). *IL hooking is always lower priority than standard event hooks at runtime, because the latter are effectively wrappers around the original method. ==Procedure== As an example, we're going to hook <code>Leech.Attached</code> to prevent Jungle Leeches from draining Slugcat's food. As the relevant code is in the middle of the method, a standard event hook won't work (at least not easily). <!-- See the notes for ideas on ways you could try to do this with standard event hooks. --> ===Step 1: Create an IL hook=== IL hooks are created similarly to standard event hooks. First, we must import a couple of things (in addition to what you would import for standard event hooks): <syntaxhighlight lang="csharp"> using Mono.Cecil.Cil; using MonoMod.Cil; </syntaxhighlight> Next, you can auto-generate the hooking method just as you would with a standard event hook. Pressing TAB after <code>+=</code> will create the hooking method automatically. <syntaxhighlight lang="csharp"> private void OnEnable() { IL.Leech.Attached += Leech_Attached; } private void Leech_Attached(ILContext il) { throw new NotImplementedException(); } </syntaxhighlight> You will also need to instantiate the cursor: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); } </syntaxhighlight> ===Step 2: Determine what to modify=== Before we can proceed, we need to know how to actually modify the method to get the effect we want. In <code>Leech.Attached</code>, the method checks whether the Leech in question is a Jungle Leech, then whether the creature it is attached to is a <code>Player</code> (Slugcat): <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> Ultimately, we want the method to ''not'' check whether the creature is a <code>Player</code> and just skip the entire following block of code, while is responsible for the food drain. Viewing the IL for this method reveals the following: <pre> 270 02FC ldarg.0 271 02FD ldfld bool Leech::jungleLeech 272 0302 brfalse 414 (050D) ldarg.0 273 0307 ldloc.0 274 0308 callvirt instance class PhysicalObject BodyChunk::get_owner() 275 030D isinst Player 276 0312 brfalse 340 (03F5) ldloc.0 </pre> Each row is an ''instruction''. The first column is the ''index'' of the instruction, which will aid in discussion of where we want to make our modifications. The third column is the ''OpCode'' for that instruction, which is very generally what the instruction does. A list of all OpCodes and what they do can be found on [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields Microsoft's documentation page]. The final column is the ''operand'' for the instruction. These particular instructions mean the following: {| class="wikitable" ! Index ! OpCode ! Operand ! Meaning ! Top of stack |- | 270 | <code>ldarg.0</code> | | Put argument 0 on the evaluation stack. In a non-static class method, argument 0 is always a reference to <code>this</code>. | <code>Leech this</code> |- | 271 | <code>ldfld</code> | <code>bool Leech::jungleLeech</code> | Pop an item off the stack, access its <code>jungleLeech</code> field, and put that <code>bool</code> on the stack. | <code>bool this.jungleLeech</code> |- | 272 | <code>brfalse</code> | <code>414</code> | Pop an item off the stack. If it is false, go to the instruction at index 414. Index 414 is just after the entire <code>if (this.jungleLeech) { ... }</code> block. | irrelevant |- | 273 | <code>ldloc.0</code> | | Put local variable 0 on the stack (the first local variable defined in this method). | <code>BodyChunk bodyChunk</code> |- | 274 | <code>callvirt</code> | <code>instance class PhysicalObject BodyChunk::get_owner()</code> | Pop an item off the stack, and call its <code>get_owner</code> property getter, and put the result on the stack. | <code>PhysicalObject bodyChunk.owner</code> |- | 275 | <code>isinst</code> | <code>Player</code> | Pop an item off the stack. Put a <code>bool</code> on the stack corresponding to whether it is an instance of <code>Player</code>. | <code>bool (bodyChunk.owner is Player)</code> |- | 276 | <code>brfalse</code> | <code>340</code> | Pop an item off the stack. If it is false, go to the instruction at index 340. Index 340 is just after <code>if (bodyChunk.owner is Player & ...) { ... }</code>. | irrelevant |} Instructions 270 and 271 correspond to <code>if (this.JungleLeech)</code>, with 272 skipping the entire code block if it is false. Instructions 273 through 275 correspond to <code>if (bodyChunk.owner is Player)</code>, with 276 skipping just the code block that affects only Slugcat if it is false. While the second conditional here is compound, conditionals are broken into their individual parts and tested individually at the IL level. This is how [[w:Short-circuit evaluation|short-circuit evaluation]] is implemented: <code>(bodyChunk.owner is Player && somethingElse)</code> has no need to evaluate <code>somethingElse</code> if <code>bodyChunk.owner is Player</code> is false. We want to have the code not even bother with checking if <code>bodyChunk.owner is Player</code> and always skip the Slugcat-specific block (which is what instruction 276 does). ===Step 3: Find the instructions of interest=== While we ''could'' tell the cursor to move directly to the index of the instructions we want to modify, that won't work reliably if any other mod IL hooks this method and changes the number of instructions. Instead, the better procedure is to ''search'' for a sequence of instructions. How many instructions should be included in this sequence is subjective. Too few, and there's a chance your hook will land somewhere it shouldn't; too many, and there's a chance another hook will modify code inside what you are trying to match, and your hook matches nothing and fails. In this example, matching instructions 270 through 276 should suffice. We tell our <code>ILCursor</code> to search for a specific sequence of instructions with <code>GotoNext</code>: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); } </syntaxhighlight> This will tell the cursor to find an <code>ldarg.0</code> instruction, followed by a <code>ldfld</code> instruction with <code>jungleLeech</code> as the operand, et cetera. Crucially, it must find all seven of these instructions in order with no gaps. Hopefully, using the <code>Match</code> methods is fairly straightforward given their required arguments (which Visual Studio will show you). Some other examples of matching are presented [[#Matching|in the notes]]. If successful, this will place the cursor at index 270 - the beginning of the instruction sequence we searched for. If it fails, an exception is thrown and this hook does not get applied. ===Step 4: Modify the instructions=== From earlier, we want to insert instructions to make the method skip checking whether <code>bodyChunk.owner is Player</code> and the following block. This just involves inserting an unconditional branch instruction. However, we have to tell it ''where'' to branch to, so we have one extra step of grabbing a reference to the instruction we want to branch to. Because we told the cursor to look for the entire sequence of 7 instructions, we can be sure they all exist here, and we don't have to use <code>GotoNext</code> to search again. We do the following to achieve this: *<code>c.Index += 6;</code> Jump to the instruction that will skip the food drain code (276). *<code>ILLabel inst = (ILLabel)cursor.Next.Operand;</code> Grab the operand of this branch instruction - which is a reference to the instruction it branches to - and store it locally. *<code>c.Index -= 3;</code> Jump back to just before where the method is checking whether <code>bodyChunk.owner is Player</code> (273). *<code>cursor.Emit(OpCodes.Br, inst);</code> Insert, or ''emit'', an instruction to branch unconditionally to the instruction we referenced earlier, skipping the food drain block. This is what our hooking method looks like now: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Br, inst); } </syntaxhighlight> What we've effectively done is changed this piece of <code>Leech.Attached</code>: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> into this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (false && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> We've now achieved exactly what we wanted but, for the sake of example, we will now attach this behavior to the value of a <code>Configurable<bool></code> (e.g., from a Remix <code>OptionInterface</code>) to illustrate how to reference things in the current context for the IL context. ===Step 5: Use a delegate to access the current context from the IL context=== We'll assume that you have already set up a <code>Configurable<bool></code> and an <code>OptionInterface</code> to allow toggling it, and that it is stored in the static field <code>Options.foodDrainToggle</code>. Although it would be possible to reference <code>Options.foodDrainToggle</code> with some specific sequence of instructions, we can give the <code>ILCursor</code> a ''delegate'' that we write in the current context instead, and it will store that delegate to use again in the IL context when the method is actually run. <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); </syntaxhighlight> The type argument <code>Func<bool></code> indicates that the delegate takes no arguments (and thus removes nothing from the evaluation stack), but returns a boolean (which is then put on the stack). This needs to be placed just before the branch instruction we inserted earlier, which also needs to be changed to a conditional branch (<code>brfalse</code>) so that it actually checks the boolean we just put on the stack. Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.EmitDelegate<Func<bool>>(() => Options.foodDrainToggle.Value); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> Note that when we emit, the cursor also moves forward, so we don't have to bump up the <code>Index</code> before inserting the next instruction. It is worth emphasizing that if any instruction we insert (including delegates) puts something on the evaluation stack, there ''must'' be an instruction that removes it from the stack (which, in this case, <code>brfalse</code> does), lest we leave the stack [[#Stack balance|unbalanced]] and cause the hook to fail. The equivalent C# code now looks like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> ===Step 6: Use a delegate to access the IL context from the current context=== We can put just about anything we want into the delegate. If we wanted to have Slugcat be [https://rainworld.miraheze.org/wiki/User:Alphappy/Live/Slowing slowed] while a Jungle Leech is attached, we could change our delegate to take in the <code>BodyChunk</code> that the original method already stored as a local: <syntaxhighlight lang="csharp"> cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); </syntaxhighlight> In contrast to earlier, this delegate takes a <code>BodyChunk</code> as input, which we must put on the stack before calling this delegate. Fortunately, because this <code>BodyChunk</code> is stored as a local already where our instructions are being inserted, that is very simple: <syntaxhighlight lang="csharp"> cursor.Emit(OpCodes.Ldloc, 0); </syntaxhighlight> Our hook now looks like this: <syntaxhighlight lang="csharp"> private void Leech_Attached(ILContext il) { ILCursor cursor = new ILCursor(il); cursor.GotoNext( x => x.MatchLdarg(0), x => x.MatchLdfld<Leech>("jungleLeech"), x => x.Match(OpCodes.Brfalse), x => x.MatchLdloc(0), x => x.MatchCallvirt<BodyChunk>("get_owner"), x => x.MatchIsinst<Player>(), x => x.Match(OpCodes.Brfalse) ); cursor.Index += 6; ILLabel inst = (ILLabel)cursor.Next.Operand; cursor.Index -= 3; cursor.Emit(OpCodes.Ldloc, 0); cursor.EmitDelegate<Func<BodyChunk, bool>>((BodyChunk bodyChunk) => { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } return Options.foodDrainToggle.Value; }); cursor.Emit(OpCodes.Brfalse, inst); } </syntaxhighlight> The equivalent C# code now looks something like like this: <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (bodyChunk.owner is Player player) { player.slowMovementStun = Mathf.Max(player.slowMovementStun, 10); } if (Options.foodDrainToggle.Value && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> You may notice that we ultimately end up testing whether <code>bodyChunk.owner is Player</code> twice (i.e., the relevant instructions are duplicated in the resultant IL). We could've instead moved our delegate to just past the original <code>bodyChunk.owner is Player</code> check so we don't have to make that check in our delegate. In that regard, what we've done here is inefficient, but it nonetheless demonstrates how to use something currently on the evaluation stack (that is, in the IL context) in the current context. ===Debug: View the modified IL=== If you add <code>Debug.Log(il.ToString());</code> to the end of your hook, it will print the modified method. You will notice that this puts hundreds of lines in the log - thousands for longer methods. As such, it is best to not print this unless you are debugging. Assuming you did all of the above, you should see the following in the middle of the printout: <pre> IL_02fc: ldarg.0 IL_02fd: ldfld System.Boolean Leech::jungleLeech IL_0302: brfalse IL_050d IL_0000: ldloc V_0 IL_0000: ldc.i4 0 IL_0000: call T MonoMod.Cil.RuntimeILReferenceBag/InnerBag`1<System.Func`2<BodyChunk,System.Boolean>>::Get(System.Int32) IL_0000: call TResult MonoMod.Cil.RuntimeILReferenceBag/FastDelegateInvokers::Invoke<BodyChunk,System.Boolean>(T1,MonoMod.Cil.RuntimeILReferenceBag/FastDelegateInvokers/Func`2<T1,TResult>) IL_0000: brfalse IL_03f5 IL_0307: ldloc.0 IL_0308: callvirt PhysicalObject BodyChunk::get_owner() IL_030d: isinst Player IL_0312: brfalse IL_03f5 </pre> This shows ''offsets'' and not indices as dnSpy did. They are not sequential and not unique for our added IL, but they still allow us to make sure our hook is doing what we intended - for instance, we can see the <code>ldloc</code> and the <code>brfalse</code> we explicitly added with <code>Emit</code>. We also see three instructions that MonoMod added to call our delegate. They look messy because of how type arguments must be passed around, but all they do is *put an identifier for our delegate on the stack; *call a method to retrieve the delegate; and *call a method to invoke the delegate. For completeness, here's what these five new instructions mean: {| class="wikitable" ! OpCode ! Operand ! Meaning ! Top of stack |- | <code>ldloc</code> | <code>V_0</code> | Put local variable 0 on the stack (the first local variable defined in this method). | <code>BodyChunk bodyChunk</code> |- | <code>ldc.i4</code> | <code>0</code> | Put the integer 0 on the stack. | <code>int 0</code><br><code>BodyChunk bodyChunk</code> |- | <code>call</code> | <code>T ...InnerBag<Func<BodyChunk, bool>>::Get(...)</code> | Call MonoMod's <code>InnerBag.Get</code>. Because this takes one input, this also pops one item off the stack.<br> When our hooking method ran, MonoMod gave our delegate an identifier of <code>0</code>.<br> <code>InnerBag</code>, when given that identifier, will return our delegate.<br> Put the resulting <code>Func<BodyChunk, bool></code>, which is our delegate, on the stack. | <code>Func<BodyChunk, bool> delegate</code><br><code>BodyChunk bodyChunk</code> |- | <code>call</code> | <code>TResult ...FastDelegateInvokers::Invoke<BodyChunk, bool>(...)</code> | Call MonoMod's <code>FastDelegateInvokers.Invoke</code>. This will pop a number of items off the stack equal to the number of arguments to the delegate plus one.<br> In our case, it will take two arguments, which are expected to be the delegate and a <code>BodyChunk</code>.<br> MonoMod will then ''invoke'' our delegate, passing the <code>BodyChunk</code> as the sole argument.<br> Put the resulting <code>bool</code> (the <code>TResult</code> of our delegate) on the stack. | <code>bool delegate(BodyChunk bodyChunk)</code> |- | <code>brfalse</code> | <code>IL_03f5</code> | Pop an item off the stack. If it is false, go to the instruction at offset 03f5. Offset 03f5 is just after <code>if (bodyChunk.owner is Player & ...) { ... }</code>. | irrelevant |} Note that the five instructions we've added collectively push to and pop from the stack the same number of times (four, in this case). This is necessary for [[#Stack balance|stack balance]]. ==Notes== ===Stack balance=== If you get the exception <code>System.InvalidProgramException: Invalid IL code in ...: ret</code>, you've left the stack unbalanced. The number of objects on the stack before and after a method executes must be equal. If the stack is ''unbalanced'' - that is, more things are placed on the stack than are removed for a given method, or vice versa - the IL hook will fail. It is therefore important to understand [https://learn.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes?view=net-7.0#fields how each OpCode interacts with the stack]. Most instructions pop one object, push one object, or both - but some instructions may pop or push more than one object depending on their operand. ===Failure to match=== If you get the exception <code>System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.</code>, your cursor failed to find the instructions requested in a <code>Goto</code>. Most likely, it means that you've just specified one of your <code>Match</code>es incorrectly. This can also happen if you try to match a block of instructions that another IL hook modifies before yours. This is an unlikely circumstance, but becomes more likely as the number of instructions to match increases. ===Find=== <code>ILCursor</code> offers <code>FindNext</code> and <code>FindPrev</code> as an alternative to the <code>Goto</code> methods. While <code>Goto</code> requires no gaps in the sequence of requested instructions, <code>Find</code> allows any gaps, as long as at finds the instructions in the requested order. For most hooks you write, you will ''not'' want to use <code>Find</code> methods without very carefully considering how specific your searched instructions are. For instance, if you try to <code>Find</code> the instructions associated with putting <code>this.abstractCreature</code> on the stack - which involves <code>ldarg.0</code> as the first instruction - the cursor will land on the first time that <code>this</code> is put on the stack for any reason, so long as the remaining <code>ldfld</code> instruction associated with <code>this.abstractCreature</code> is ''somewhere'' further along in the method. Of course, if <code>this.abstractCreature</code> ''happens'' to be the first time <code>this</code> is put on the stack, it will still work. ===TryGoto and TryFind=== <code>ILCursor</code> offers <code>Try</code> versions of <code>Goto</code> and <code>Find</code> methods which will not raise an exception if they can't find the instructions you requested. For most hooks you write, you will ''not'' want to use the <code>Try</code> versions (in general, silent exception suppression is a bad thing). The cursor will simply not move if it can't find what you requested, meaning your next commands to inject new instructions will likely fail or cause unintended behavior since they are not where you intended them to be. ===Matching=== It is always possible to match an instruction using just <code>Match(OpCode)</code>. This will disregard the operand completely. For some instructions, it is often easier to just not bother trying to match the operand. This is especially true of branches, which require a reference to the instruction being branched to in order to be robust. You should use the more specific Match methods whenever possible, since many sequences of instructions are fairly common when operands are ignored (in our example, <code>ldarg.0</code> <code>ldfld</code> <code>brfalse</code> is a ''very'' common sequence). {| class="wikitable mw-collapsible mw-collapsed sortable" !colspan="3"|Examples of how to match common instructions |- !Instruction as displayed by dnSpy !Matching method !Comment |- |<code>brfalse 414</code> |<code>MatchBrfalse(instruction)</code> |To match this way, you need a reference to the instruction in the operand. It's usually sufficient to just <code>Match</code> the OpCode instead. |- |<code>call float32 [UnityEngine.CoreModule]UnityEngine.Mathf::InverseLerp(float32, float32, float32)</code> |<code>MatchCall<Mathf>("InverseLerp")</code> |Assuming that you are <code>using UnityEngine</code>. |- |<code>callvirt instance class PhysicalObject BodyChunk::get_owner()</code> |<code>MatchCallvirt<BodyChunk>("get_owner")</code> |The type information - <code>instance class PhysicalObject</code> - can be ignored. |- |<code>callvirt instance valuetype Room/Tile/TerrainType Room/Tile::get_Terrain()</code> |<code>MatchCallvirt<Room.Tile>("get_Terrain")</code> | |- |<code>isinst Player</code> |<code>MatchIsinst<Player>()</code> | |- |<code>ldarg.0</code> |<code>MatchLdarg(0)</code> | |- |<code>ldc.i4.1</code> |<code>MatchLdcI4(1)</code> | |- |<code>ldfld bool Leech::jungleLeech</code> |<code>MatchLdfld<Leech>("jungleLeech")</code> | |} ===Representing the IL in equivalent C#=== Note that there are several equivalent ways that you could represent the changes we've made here in this example in C#. For instance, instead of <syntaxhighlight lang="csharp"> if (this.jungleLeech) { if (false && bodyChunk.owner is Player && ...) { ... } ... } </syntaxhighlight> we could depict this equivalently as <syntaxhighlight lang="csharp"> if (this.jungleLeech) { goto LabelWeJustMade; if (bodyChunk.owner is Player && ...) { ... } LabelWeJustMade: ... } </syntaxhighlight> which might feel more natural given that we've added an unconditional branch at this step. The purpose of depicting our change as an affix to the conditional instead is to illustrate that this is fundamentally how conditionals work - they are simply chains of loading things onto the stack, testing something about those things, and then branching under some condition. ===Declaring a delegate=== For the purpose of modding Rain World, the simplest way to declare a delegate is generally to use a [https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/lambda-expressions lambda expression], but there are [https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/delegates/how-to-declare-instantiate-and-use-a-delegate other ways] to declare a delegate. Of particular note is that lambda expressions are ''anonymous'' - that is, they have no name - meaning that any exceptions that include them in the stack trace will become a bit harder to understand. This generally does not matter unless you are using many such delegates that reference each other. <!-- ===Other ways we could've conducted our example=== There are a few ways we could prevent Jungle Leech food drain with standard event hooks, each with their own side effects. *We could check whether what the creature being grabbed is Slugcat (<code>this.grasps[0]?.grabbed is Player</code>), and forgo the <code>orig</code> call if so. This would: **disable their physics completely. **potentially break any other mod that also hooks <code>Leech.Attached</code>. **disable the safeguard that stuns Leeches in "forbidden" rooms (such as shelters and gates). **prevent them from detaching once they've been out of water for long enough. **prevent them from being wiggled off. *We could hook <code>Player.SubtractFood</code> instead and prevent the food drain there if any Leech is attached (which we could check with a <code>foreach</code>). This would: **not disable the stun and exhaustion associated with being drained at zero food. **make Gourmand regurgitation and Artificer's crafting free while any Leech is attached. **hurt performance slightly every time <code>Player.SubtractFood</code> is called. --> 9f4738476669880b97c2606529abf28c0f46f77f Dev Tools 0 84 565 508 2023-10-11T17:56:26Z CurrentlyPending 309 Added 5, 6, and 7 keys for spawning key story items in the keys table. wikitext text/x-wiki {{Cleanup}} == Dev Tools == The '''Dev Tools''' are a collection of in-game tools used by the developers for testing the game and editing map properties. They are a good starting point for modders, as the tools are fairly easy to use, and provide some basic modding capabilities. They come installed with Rain World 1.9 and can be enabled in the Remix menu. For 1.5, they can be installed from the Legacy section of [http://www.raindb.net/ RainDB]. === Controls === The following keyboard shortcuts are available for use once the Dev Tools have been activated in-game. ==== Main controls ==== {| class="wikitable" |+ |- ! '''Key''' !! '''Function''' |- | O || Enables/Disables Dev Mode. While Dev mode is active, some yellow text will be shown at the top of the screen showing that it is active, and also showing the current map name. |- | H || Opens/closes the main Dev Tool interface. |- | M || Shows various useful debug information, like number of creatures active in the region, exact time left until the rain, creature relationship statuses, numerical identifiers for pipes and spawn locations, and pixel/tile coordinates at the mouse location. A tip for expanding functionality can be found on the [[DebugMouse]] page. |- | P || Displays tile accessibility for each creature type. Use arrow keys to select a creature type, then click a tile in the room to see every place the creature can reach from that tile. |- | Q || Fills Slugcat's food meter by one pip. |- | R || Restarts the cycle from the shelter. |- | A || Reduces physics tickrate when held, making the game run in slow-motion. |- | S || Increases physics tickrate when held, making the game run as fast faster (150% speed max in vanilla, potentially more if a mod uncaps FPS) |- | V || Teleports Slugcat to the location of the mouse. |- | W || Flings slugcat in the general direction of mouse motion. Works incorrectly in multiscreen rooms. |- | F || Pulls batflies towards the location of the mouse. |- | B || Drags all creatures/entities to the location of the mouse (except Slugcat and Batflies). |- | G || Flings all vultures skywards. |- | N || Offsets the camera based on the mouse position. |- | E || Sets the migratory destination of every creature in the region to the current room. |- | U || Reloads all sound samples. |- | I || Shows a log of all sound effects played. |- | K || Shows UnityEngine.Debug.Log (normally routed to ConsoleLog.txt) output on screen (Extended Devtools). |- | 5 || Spawns Spearmasters Pearl. |- | 6 || Spawns Hunters Neuron. |- | 7 || Spawns a Rarefraction Cell. |} ====Menu controls==== These are additional Dev Tools commands available on the title screen/region select screens. {| class="wikitable" |+Menu controls |- ! '''Key'''!!'''Function''' |- |N+Jump||Allows you to reposition the layers in the background image with the mouse. |- |B||Saves the new positions of the layers to file. |} ====Cutscene controls==== These are not useful in the current version of Dev Tools, as you can't save these changes, and the cutscene doesn't pause while this mode is active, like it probably is supposed to. {| class="wikitable" |+Cutscene controls |- !'''Key'''!!'''Function''' |- | M||Activate/Deactivate cutscene editing mode. |- |Left Click|| Select and drag keyframes around. |- |J||Add a new keyframe. |- |K||Remove a keyframe. |- |O||Change depth of selected keyframe. |- |L|| Offset all keyframes. |- |I||Test playback of cutscene. |} ==Interface Tabs== Once opened the Dev Tool interface is broken up into five different tabs, <div class="wikitable"><tabber> |-| Room settings= This tab mostly contains settings for base room visuals, such as palette, cloud cover and terrain wetness. === General Controls === {| class="wikitable" |+ |- ! '''Control''' !! '''Function''' |- | Save || Saves the current effects and room settings to a file inside the region's World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. |- | Inherit from template || Will set the values stored in a specific template the region has to this room. |- | Save as template || Saves the current room's settings as a template for easy re-use. |} === Room settings menu === ==== G.O ==== Controls the game over sequence when the rain timer expires. * Rain: As it says on the tin. * Flood: Room will slowly fill up from its set water height. * Flood and rain: The sky is death, and the room floods * None: Will cause no visual effects, and screen rumbling will be disabled * Thunder: Lightning effects in the room will speed up animation.However no actual deadly effects will happen. To do an under hang style lightning walls effect. you will need to add an "ElectricDeath" room effect with a 100% modifier. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Rain Intensity || Increases or decrease how hard the rain will impact the player. Default is 100%. Lower amounts will eventually not kill the player, but instead only hamper their jumps. |- | Rumble Intensity || Similar to rain intensity, Controls the screen shake of the room when the rain timer expires. This does not apply to rooms with a G.O of "none", as by default those will not shake anyway. |- | Ceiling Drips || Controls how wet a room is. The higher the value, the more drips will spawn. This will only apply for a few moments at the beginning of a cycle, unless "Wet terrain" is turned on. |- | Waves || Speed, length, and amplitude of water waves. |- | Clouds || Changes the cloud cover of an area. Will be forced to 100% when the room has the sun disabled. ( This is changed in the official editor when exporting a level. ) |- | Grime || Creates an oil like film over the edges and raised bits of tiles. Also causes minor distortions on the screen. |- | Random Item Density || Controls how often rocks will spawn on the ground of the room. |- | Random Item Spear Percent || How often those random rocks will be spears |- | Water Light || The modified intensity of light sources placed underwater. |} === Palette Menu === ==== Palette ==== {| class="wikitable" |+ Palette menu controls |- ! '''Control''' !! '''Function''' |- | Palette || Rooms in Rain World use palettes to decide how they draw on screen. These colors can be changed during run time and easily modified and saved to tweak rooms on the fly. By default there are 35 palettes in vanilla rainworld. However more can be added through modding. |- | Effect color A/B || Controls the palette of effects applied from the official editor. The official editor can paint effects to use one of these palettes specifically. Allowing you to draw plants using palette A, and daddy corruption using palette B, to name an example. Both palettes can be configured like the normal palette menu. |- | Fade Palette || Changing this from "none" will enable a percent slider for every camera in the room, and will allow you to select a secondary palette. These sliders will allow you to fade between the primary palette, and this secondary fade palette. Allowing you to do visual transitions as you progress through rooms, or to simply create a blended set of colors between two specific palettes. The image below shows a fade at 0%, 50% and 100%. Slowly changing the room's colors between the two palettes based on the slider. |} [[File:Fadepalette example.png|1440px|center|border]] ===Effects Library=== This menu will allow you to select various effects you want to happen in a room. However, most of these will require the room to be saved, and then reloaded. Simply dying, and returning to the room will do this. Clicking an effect in this menu will add it, and again will remove it. Most effects require a save + reload, so do not be surprised if the effect does not show up at all when you add it at first! Gameplay Lighting Decorations Insects WaterAndFlooding {|class="wikitable" |- ! '''MSC''' !! '''Effect''' !! '''Description''' !! '''Showcase''' |- !colspan="3"|Gameplay |- | style="color: green;" | No || ZeroG || Decreases gravity, at 100% you will gain zeroG controls like the inside of Five Pebbles. |- | style="color: green;" | No || BrokenZeroG || Controls how often the above effect shuts down and turns back on. Allows you to have partial anti-gravity with different levels of gravity, and not just fully on or off gravity. |- | style="color: green;" | No || SSSwarmers || Causes neurons to spawn randomly throughout the room. |- | style="color: green;" | No || SSmusic || Plays Random gods at the intensity of the percent slider. Requires zero gravity. Fades in and out when gravity is broken. |- | style="color: green;" | No || ElectricDeath || Causes sparks and zaps when the raintimer expires. Any value under 100% will only cause visual sparks. at 100% it will knock slugcat around, and eventually kill them. |- | style="color: green;" | No || BorderPushBack || Will shove slugcat away with increasing force. NOTE: Checks camera boundaries instead of geometry boundaries, its behaviour is thus ''resolution dependent''. |- | style="color: green;" | No || DayNight || Allows the room to have a night mode. Must be used in tandem with the DayNightSettings object. |- | style="color: red;" | Yes || RoomWrap || Objects and creatures that leave one side of the room will appear on the other side as well. |- | style="color: red;" | Yes || DustWave || Makes a terrifying sandstorm sweep across the room when the rain timer runs out. |- !colspan="3"|Lighting |- | style="color: green;" | No || SkyBloom || Increases how fuzzy/bloomy the sky's light is. || [[File:Effect 2.png|frameless|Applying the effect]] |- | style="color: green;" | No || LightBurn || How overwhelming the "baked in" light placed in the official editor is. A good example is the bright lights seen near the start of the Miros bird tunnel in subterranean. || [[File:Effect 3.png|frameless]] |- | style="color: green;" | No || SkyAndLightBloom || A mix between skybloom and light burn at the same time is more intense. || [[File:Effect 4.gif|frameless|Applying the effect]] |- | style="color: green;" | No || Bloom || Similar to SkyBloom, but applies to lights. || [[File:Effect 5.png|frameless]] |- | style="color: green;" | No || Fog || Creates a white cloudy effect at layer 1. Not compatible with SkyBloom, LightBurn, SkyAndLightBloom and Bloom. || [[File:Effect 6.png|frameless]] |- | style="color: green;" | No || SunBlock || Makes it so sun light doesn't show as if a shadow is covering everything.Allows the two projector effects below to work properly. |- | style="color: green;" | No || ProjectedScanLines || Adds vertical and horizontal projected lines that slowly scroll across the room. |- | style="color: green;" | No || SuperStructureProjector || Causes glowing lines and circles around CoralNeurons, the percent slider controls flashing symbols and lines in various intensities. |- | style="color: green;" | No || Darkness || Darkens the room's palette. |- | style="color: green;" | No || Brightness || Brightens the room's palette. |- | style="color: green;" | No || Contrast || Increases contrast on the room's palette. |- | style="color: green;" | No || Desaturation || Desaturates the room's palette. |- | style="color: green;" | No || Hue || Shifts the hue of the room's palette. |- | style="color: green;" | No || DarkenLights || Darkens the light color on the room's palette. |- | style="color: green;" | No || WaterLights || Changes the visuals of light emitting objects that are underwater. |- !colspan="3"|Decorations |- | style="color: green;" | No || SkyDandelions || Adds floating puffs in the air, a Sky Islands effect. || [[File:Effect 1.png|frameless|The effect at 100%]] |- | style="color: green;" | No || Lightning || Creates flashes, and makes the terrain glow. Certain palettes break this effect. Plays a zapping sound effect. |- | style="color: green;" | No || BkgOnlyLightning || Similar to above, However it only causes the background to flash, and does not require special palettes. Plays a zapping sound effect. |- | style="color: green;" | No || ExtraLoudThunder || Changes the thunder sound effects of Lighting/BkgOnlyLightning to a louder and more violent version. |- | style="color: green;" | No || GreenSparks || Underhang, and the Legs' green sparkles. |- | style="color: green;" | No || VoidMelt || Void fluid camera effect seen near the end of the game. Covers the screen in maple syrup. Causes slowdown automatically. |- | style="color: green;" | No || CorruptionSpores || Spawns black specks that float in the air, as seen near unfortunate development. Requires zero gravity, or broken zero gravity at full strength to appear. |- | style="color: green;" | No || AboveCloudsView || Draws the Wall's background in the room. This is tied directly to the room's Y location on the map. The top of the wall is at Y -2064. Use the regions map file to place your room at the height required for the effect you need. |- | style="color: green;" | No || RoofTopView || Draws the city above FivePebble's in the background, and applies a dusty effect behind slugcat as they move and jump. |- | style="color: green;" | No || VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | style="color: green;" | No || FairyParticles || Generates screen-wide particles. Should be used in tandem with the FairyParticlesSettings placed object. |- | style="color: green;" | No || Coldness || Causes slugcat to emit cold breath particles. |- | style="color: green;" | No || HeatWave || Applies a heat distortion shader over the room. |- | style="color: green;" | No || DustPuffs || Causes slugcat to emit puffs of dust under their steps. |- | style="color: green;" | No || VoidSpawn || Causes void free void spawn to appear swimming throughout the room. |- | style="color: red;" | Yes || Advertisements || Overseers will show random advertisement projections. |- !colspan="3"|Insects |- | style="color: green;" | No || Flies || Spawns small flys that buzz around the room and land on objects. |- | style="color: green;" | No || FireFlies || Spawns tiny glowing yellow bugs throughout the room, that grow in intensity as the cycle progresses. |- | style="color: green;" | No || TinyDragonFly || Spawns tiny bugs that fly around plants. |- | style="color: green;" | No || RockFlea || Spawns tiny bugs that hop around on the ground in clusters. |- | style="color: green;" | No || RedSwarmer || Spawns small, bright red bugs that fly around slowly. |- | style="color: green;" | No || Ant || Spawns small jumping bugs. |- | style="color: green;" | No || Beetle || Spawns small beetles that slowly fly around the room. |- | style="color: green;" | No || WaterGlowWorm || Spawns small worms that swim around in water. |- | style="color: green;" | No || Wasp || Spawns small wasps that quickly dart between walls. |- | style="color: green;" | No || Moth || Spawns small white moths which slowly flutter around the room. |- !colspan="3"|WaterAndFlooding |- | style="color: green;" | No || LightRain || Causes a gentle cosmetic version of death rain to be constantly present. |- | style="color: green;" | No || LightRain || Causes the death rain to be constantly present. Not hard enough to kill, but only to push around. |- | style="color: green;" | No || BulletRain || Causes bullet rain to be constantly present. |- | style="color: green;" | No || BulletRainFlux || Causes bullet rain to fluctuate in intensity and presence. Requires the BulletRain effect. |- | style="color: green;" | No || WaterFluxFrequency || Adjusts how fast water in the room fluctuates. |- | style="color: green;" | No || WaterFluxMinLevel || Adjusts the lowest point the water will descend to. |- | style="color: green;" | No || WaterFluxMaxLevel || Adjusts the highest point the water will rise to. |- | style="color: green;" | No || WaterFluxMinDelay || Adjusts how long the water should pause at the lowest level. |- | style="color: green;" | No || WaterFluxMaxDelay || Adjusts how long the water should pause at the highest level. |- | style="color: green;" | No || WaterFluxSpeed || Adjusts how quickly the water should fluctuate. |- | style="color: green;" | No || WaterFluxOffset || Shifts the WaterFlux cycle to happen later. |- | style="color: green;" | No || WaterFluxRumble || Adjusts how much the room should rumble while the water is fluctuating. |- | style="color: green;" | No || LethalWater || Makes water deadly to anything that touches it. |- | style="color: green;" | No || SilenceWater || Turns off the default ambient water noises. |- | style="color: green;" | No || WaterViscosity || Adjusts how thick the water is. |- | style="color: green;" | No || WaterDepth || Adjusts the visual sublayer the water appears on. Default is sublayer 0 or 1, but this effect allows the water to be placed on any sublayer, even behind the playable area. |- | style="color: red;" | Yes || InvertedWater || Puts water on the ceiling. |- | style="color: green;" | No || DirtyWater || Changes the water's appearance to be more dirty. |- | style="color: red;" | Yes || FastFloodDrain || When precycle flooding is ending, makes the room drain faster. |- | style="color: red;" | Yes || FastFloodPullDown || When precycle flooding is ending, treats the room as if it were lower. |- | style="color: green;" | No || LavaSurface || Changes the water's appearance to be more like lava. |- !colspan="3"|Unsorted |- | style="color: green;" | No || VoidSea || Spawns voidworms, draws a fade. Swimming downward, or falling downwards, will eventually bring you to the void sea. Triggers the ending sequence when entered. |- | style="color: green;" | No || FakeGate || Adds various dysfunctional visuals to make the room look like a gate. |- | style="color: green;" | No || PixelShift || Moves the camera center when playing in a thinner resolution. Used to keep relevant details on-screen. |- | style="color: red;" | Yes || BrokenPalette || Changes the room's palette to use the 1.5 broken palette. |} '''Note''': Some effects are mutually exclusive - if multiple of these effects are applied, not all of them will work properly. Some of them are partially compatible, but most of them override entirely. The order of these is the priority - effects that are higher in the list will override lower ones.* <syntaxhighlight lang=""> SkyBloom, SkyAndLightBloom, Lightning, LightBurn, Fog, Bloom, VoidMelt </syntaxhighlight> |-| Objects= Allows placing various devtools objects. === General controls === === Save === Saves the current objects to a file inside the region’s World folder, named ROOMNAME_settings.txt Some objects do not spawn instantly, and thus need to be saved, and then reloaded by dying and returning to the room to see the changes. === Mouse input: === Objects can be grabbed with the left mouse button. Releasing will put them down. Dragging the object to the bottom left into the trash bin box will remove it. Some objects will only be removed completely by reloading the room entirely. == Object Library == {|class="wikitable" !width="6%"| '''<u>MSC</u>''' !width="20%"| '''<u>Object</u>''' !width="62%"| '''<u>Description</u>''' !width="12%"| '''Requires Reload''' |- !colspan="4"|Gameplay |- | style="color: green;" | No | Filter | Spawns a zone where objects can be configured to only spawn on certain difficulties. | Yes |- | style="color: green;" | No | NoSpearStickZone | Spears will always bounce off walls inside this circle. | Yes |- | style="color: green;" | No | PlayerPushback | Pushes the player away from a point with increasing force. | Yes |- | style="color: green;" | No | CentipedeAttractor | Draws centipedes towards it at the start of a cycle. These centipedes will even ignore slugcat till they reach their destination. | Yes |- | style="color: green;" | No | VoidSpawnEgg | Adds a little void ghost thing that is trapped and can be freed if touched by slugcat. Only visible when slugcat has obtained the mark from Five Pebbles. May need other unknown conditions to be visible. | Yes |- | style="color: green;" | No | ScavengerOutpost | Scavenger toll. Trade pearl for passage through. Second dot sets range from main dot. Direction from the middle dot to the second dot controls the angle of the dear totem’s pole. The skull and pearls hanging from it can be changed using the random seed sliders, and the angle the skull faces with the “angle” slider. Requires scavengers to be added to the world file, and scavenger doors be placed in the world. Scavengers will naturally migrate to it. Will also spawn a cache of spears around it for the scavengers. | Yes |- | style="color: green;" | No | TradeOutpost | Scavenger merchant. Trade pearls for items. Second dot sets range from main dot. | Yes |- | style="color: green;" | No | ScavengerTreasury | Spawns random scavenger items in the radius around it. Explosive spears, bombs, and lanterns. | Yes |- | style="color: green;" | No | ExitSymbolShelter | Forces a door’s symbol to show as a save room. Often used on the other side of gates, where you cannot control what the door links to, but still need it to show a save room on the other side. | Yes |- | style="color: green;" | No | ExitSymbolAncientShelter | Forces a door’s symbol to show as an ancient shelter room. Would be used used on the other side of gates, where you cannot control what the door links to, but still need it to show an ancient shelter room on the other side. | Yes |- | style="color: green;" | No | ExitSymbolHidden | Will cause a door’s symbol to hide. Used to make the entrances to scavenger caches, or to hide doors under corruption in Five Pebbles. | Yes |- | style="color: green;" | No | NoLeviathanStrandingZone | Creates an area that pushes leviathans, useful for placing down in places where leviathans get stuck. | |- | style="color: green;" | No | NeuronSpawner | Spawns neurons within the area | Yes |- | style="color: green;" | No | DeathFallFocus | Makes the death gradient more obvious | |- | style="color: green;" | No | Vine | Places a climbable vine in the room. | |- | style="color: red;" | Yes | KarmaShrine | Places a 'karma shrine,' which grant maximum karma on contact and recharge Saint's Ascension ability. | |- | style="color: red;" | Yes | MSArteryPush | The same as PlayerPushback, but intensity is inversly correlated with the room's gravity. That is, when there is no gravity, the push intensity is equal to PlayerPushback. When there is normal gravity, there is no push. | |- !colspan="4"|Consumable |- | style="color: green;" | No | ReliableSpear | Spawns a spear in this location with a much higher chance then normal. If you need a required spear, use the official level editor to place one in the room’s file. | Yes |- | style="color: green;" | No | DataPearl | Spawns a generic white pearl. | Yes |- | style="color: green;" | No | UniqueDataPearl | Spawns a data pearl with a set lore index. Requires advanced modding setup to add lore pearls. | Yes |- | style="color: green;" | No | Dangle fruit | Spawns edible blue fruit that hang from vines. Dot’s position is where the top of the fruit will be, not the vine’s base. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | WaterNut | Spawns a blue waterNut that can be popped in water. Dot is the center of the nut, The plant will find ground to take root on. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | FlareBomb | Spawns a bomb. | Yes |- | style="color: green;" | No | PuffBall | Spawns a puffball. | Yes |- | style="color: green;" | No | Jellyfish | Spawns a jellyfish at the dot’s location. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | KarmaFlower | Spawns a karma flower. Dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | Mushroom | Spawns a mushroom. Dot is the center of the cap, the room will find the ground automatically. | Yes |- | style="color: green;" | No | SlimeMold | Places glowing edible molds on the walls and floor. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | CosmeticSlimeMold | Same as SlimeMold just smaller and not edible. | Yes |- | style="color: green;" | No | CosmeticSlimeMold2 | Another SlimeMold variant | Yes |- | style="color: green;" | No | Flylure | Spawns batfly luring plants. The dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | FirecrackerPlant | Spawns a firecracker, dot is the root of the plant. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | VultureGrub | Spawns a vultureGrub. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | DeadVultureGrub | Same as above, except prekilled. | Yes |- | style="color: green;" | No | SporePlant | Wip | |- | style="color: green;" | No | NeedleEgg | Spawns a noodlefly egg. Dot is the egg itself, it will attach to a ceiling on its own. | Yes |- | style="color: green;" | No | BubbleGrass | Spawns in the bubble grass object that allows for longer breathing. | |- | style="color: green;" | No | Hazer | Spawns a squid like creature called a Hazer. Will make a huge cloud of ink when thrown. | Yes |- | style="color: green;" | No | DeadHazer | Spawns a dead Hazer. | Yes |- | style="color: green;" | No | SeedCob | Spawns a popcorn plant, the top of the plant is at the dot. The root will automatically try to find the ground under it. Refresh time between cycles can be set with the sliders. | Yes |- | style="color: green;" | No | DeadSeedCob | Same as above, except it starts eaten, and will never refill. | Yes |- | style="color: green;" | No | HangingPearls | Places a hanging pearl chain, like the ones seen on scavenger tolls. | Yes |- | style="color: green;" | No | HangingPearls | Places a hanging pearl chain, like the ones seen on scavenger tolls. | Yes |- | style="color: red;" | Yes | DandelionPeach | Places a [https://rainworld.miraheze.org/wiki/Dandelion_Peach Dandelion Peach] | Yes |- | style="color: red;" | Yes | GooieDuck | Places a [https://rainworld.miraheze.org/wiki/Gooieduck GooieDuck] | Yes |- | style="color: red;" | Yes | LillyPuck | Places a [https://rainworld.miraheze.org/wiki/Lillypuck LillyPuck] | Yes |- | style="color: red;" | Yes | GlowWeed | Places a [https://rainworld.miraheze.org/wiki/Glow_Weed Glow Weed] | Yes |- | style="color: red;" | Yes | RotFlyPaper | Places a purple rot tentacle that holds dead neurons. | Yes |- !colspan="4"|CoralBrain |- | style="color: green;" | No | CoralStem | Places one of the nerve tree plants from inside Five Pebbles. Center dot is the root. Secondary dot is the default direction and the base.If not in zero gravity the plant will flop limply down. | Yes |- | style="color: green;" | No | CoralStemWithNeurons | Spawns the same object as above, except with neuron flies around it. May require zero gravity to spawn neurons. | Yes |- | style="color: green;" | No | CoralNeuron | Spawns a long red climbable noodly creature from inside Five Pebbles. Center dot is one end, Secondary dot is the other end. Acts as if it is always in zero gravity. | Yes |- | style="color: green;" | No | CoralCircuit | Spawns a breakable block of coral and neurons from inside Five Pebbles. Acts as if it is always in zerogravity. Center dot controls location, Second dot controls the size of it. | Yes |- | style="color: green;" | No | WallMycelia | Spawns tiny black and blue tendrils that talk to neurons, and attach to CoralNeurons. Act as if always in zero gravity. | Yes |- | style="color: green;" | No | ProjectedStars | Adds the constellation looking projections found within five pebbles. Center dot controls location, Second dot controls the size of it. Just like the SuperStructureProjector and the ProjectedScanLines effects from the effects tab, The stars will only work if the SunBlock effect is added. | Yes |- | style="color: green;" | No | ZapCoil | Adds a blue zapping and sizzling effect the tile it is placed over. Meant to be used with the ZapCoil objects in the tile editor. Strangely, it turns off and on with the BrokenZeroG effect, even though this is never seen happening in the main game. | Yes |- | style="color: green;" | No | SuperStructureFuses | Causes blinking lights and flicking dots. It is often used with the Superstructure material in the official editor’s tile editor. However it can be placed under any tileset, and will cause it to flash red and blue in various ways. | Yes |- | style="color: green;" | No | GravityDisruptor | Causes a visual distortion, blue lights, and will forcibly make slugcat push away and orbit it when close enough. Is intended to be used with the gravity machine tile/prop in the official editor. Will turn on and off automatically if brokenZeroGravity is enabled. | Yes |- | style="color: green;" | No | DeepProcessing | Causes a blue sparkling effect in background layers. The layer and intensity can be adjusted using the slider. The four points can be stretched as needed. | No |- | style="color: green;" | No | Corruption | Spawns Daddy Longlegs corruption on walls. Only the tendrils will pull you into walls, the small tumors will simply slide you around harmlessly. Tendrils are spawned automatically. The main dot controls location, second dot controls the size of the area affected.Warning: This object will crash in arena mode. | Yes |- | style="color: green;" | No | CorruptionTube | Spawns a climbable blue tendril between two points. | Yes |- | style="color: green;" | No | CorruptionDarkness | Spawns a black distorted shadow that normally appears near the corruption inside Five Pebbles. | Yes |- | style="color: green;" | No | StuckDaddy | Spawns a Daddy Longlegs locked to a specific location. This spawns a new daddy, and does not require any creature to be added to the World file.Note: It must be placed within corruption to spawn. | Yes |- | style="color: green;" | No | SSlightrod | Glowing laser lights inside Five Pebbles. Can be adjusted in both brightness, and depth into the background. | No |-!colspan="4"|Decoration |- | style="color: green;" | No | LightSource | Spawns a light that changes color based on its location. The secondary dot can be grabbed to stretch out the distance the light covers, and the slider sets how bright it is. | No |- | style="color: green;" | No | LightFixture | Spawns a light with a specific state and style of flickering. Such as fire or filtration system red lights. Is turned on and off by the BrokenZeroG effect. | Yes |- | style="color: green;" | No | Spotlight | Adds a configurable light that comes from a specific direction. The location of the Spotlight is configurable with four dots the same way configuring a decal works.The light color and layer are also configurable. | No |- | style="color: green;" | No | LightBeam | Spawns a ray of light that can be distorted and moved around by the four points that make up this object’s rectangle. Sliders control the depth per layer, as well as how bright it is per layer. The white adjustment is between using a palette color, and using white. | No |- | style="color: green;" | No | CustomDecal | Spawns a distort-able decal that can be placed and changed as needed. | No |- | style="color: green;" | No | Rainbow | Spawns a rainbow that will appear with a certain percent at the beginning of a cycle. The rainbows size, thickness, and fade can be controlled with the slider. The dots change it’s location and arch. | No |- | style="color: green;" | No | DandelionPatch | Spawns a patch of skyisland puffballs along the ground. | Yes |- | style="color: green;" | No | LanturnOnStick | Spawns a scavenger lantern on a pole. Used often by scavenger merchants. | Yes |- | style="color: green;" | No | InsectGroup | Spawns a several insects who stay inside the boundaries of the circle. Amount of insects is determined by the density. | Yes |- | style="color: green;" | No | BrokenShelterWaterLevel | If a shelter is configured to be broken on a certain difficulty, it can be flooded to a certain water level. This will set that height. | Yes |- | style="color: green;" | No | FairyParticleSettings | Settings for the FairyParticles room effect | |- | style="color: green;" | No | DayNightSettings | Configures the palette for Dusk and Night | |- | style="color: green;" | No | EnergySwirl | Places a visual of swirling energy - used by MSC in the Iterator Core rooms. | No |- | style="color: green;" | No | LightningMachine | Creates electricity strands with many customizability options. | No |- | style="color: green;" | No | SteamPipe | Creates a little steam effect | Yes |- | style="color: green;" | No | WallSteamer | Creates a little steam effect | Yes |- | style="color: green;" | No | SnowSource | Adds piles of snow on top of everything in the area | No |- | style="color: green;" | No | LocalBlizzard | Creates a blizzard shader effect in the area it's placed. | No |- | style="color: green;" | No | CellDistortion | Places a fancy distortion effect. Used most commonly in Rubicon. | No |- | style="color: green;" | No | BlinkingFlower | Places a flower on the background. Used most commonly in Outer Expanse and Undergrowth | Yes |- | style="color: green;" | No | BlinkingFlower | Adds a flower to the background. Used most commonly in Outer Expanse and Undergrowth | Yes |- | style="color: red;" | Yes | OESphere | Places an orange glowing orb. | No |- !colspan="4"|Tutorial |- | style="color: green;" | No | SuperjumpInstructions | Trigger rectangle will cause the long jump tutorial text to display. The four points can be stretched as needed. | Yes |- | style="color: green;" | No | ProjectedImagePosition | Wip, but presumably makes the yellow overseer project an image. | Yes |- | style="color: green;" | No | ReliableIggyDirection | Wip | |- | style="color: green;" | No | ScavTradeInstruction | Displays pearl trading tutorial | Yes |- | style="color: green;" | No | DeadTokenStalk | Same as above, but has nothing to unlock. | Yes |- | style="color: green;" | No | GoldToken | Spawns an arena unlocking scanplant. center dot is the location of the token, second dot is the roots. Can be configured to show up only in specific difficulties | Yes |- | style="color: green;" | No | BlueToken | Same as above, except for creature unlocks | Yes |- | style="color: Red;" | Yes | GreenToken | Same as above, except for slugcat unlocks | Yes |- | style="color: Red;" | Yes | RedToken | Same as above, except for safari unlocks | Yes |- | style="color: Red;" | Yes | WhiteToken | Places a [https://rainworld.miraheze.org/wiki/Broadcasts broadcast token] for Spearmaster | Yes |- | style="color: Red;" | Yes | DevToken | Places a [https://rainworld.miraheze.org/wiki/Developer_Commentary Dev Token] that will appear in Developer Commentary mode and will trigger the commentary | Yes |- !colspan="4"|Unsorted |- | style="color: green;" | No | TempleGuard | Spawns a guardian | Yes |- | style="color: green;" | No | GhostSpot | Triggers an echo at this location. Requires advanced modding setups to add echos. | Yes |- | style="color: green;" | No | MultiplayerItem | Adds an item of choice that can spawn in arena mode. | |- | style="color: red;" | Yes | Germinator | Does nothing, likely meant to be a consumable food type that was never implemented. | |- | style="color: red;" | Yes | BigJellyFish | Places a [https://rainworld.miraheze.org/wiki/Giant_Jellyfish Giant Jellyfish] | Yes |- | style="color: red;" | Yes | MoonCloak | Places [https://rainworld.miraheze.org/wiki/Cloak Moon's Cloak] | Yes |- | style="color: red;" | Yes | Stowaway | Places a [https://rainworld.miraheze.org/wiki/Stowaway Stowaway] | Yes |- | style="color: red;" | Yes | HRGuard | Places a Guardian that will lock all doors of the room until it is killed. | Yes |} |-| Sounds= [[File:soundTab.png|400px|right|border|]] This editor tab allows you to place various sounds into the room. Omni-directional sounds will play regardless of your location in the room, and from all directions. Directional sound is similar, you can control the direction the player will hear the sound from their speakers in. Finally spot sounds will play from a specific location in the room, with a configurable fading distance. All sounds can have their pitches and volume tweaked to fit the mood of the room. Take a peak at rooms in the vanilla game to get a sense of how loud sounds normally are in game. === General Controls === ==== Save ==== Saves the current sounds to a file inside the region’s World folder, named ROOMNAME_settings.txt. ==== Mouse input ==== Positional sounds can be grabbed with the left mouse button. Releasing will put them down. Dragging the sound to the bottom left into the trash bin box will remove it. While this tab is open, and the Bkg Drone volume is above 0%, you you can move your mouse from the left of the screen to the right, to preview the varying levels of threat music your region has. The left being the lowest, and right being maximum threat. {| class="wikitable" |+ Various controls |- ! '''Control''' !! '''Function''' |- | Bkg Drone || The volume of procedural enemy encounter music. 28% is the default volume in most areas. |- | No Threat Drone Vol || ??? |} {| class="wikitable" |+ "Create sound" controls |- ! Sound type !! Desription |- | Omnidirectional || Sounds selected with this option selected will play at a set volume regardless of location in the room. Clicking the sound again in the list will remove it. |- | Directional || Sounds selected with this option will play from a specific direction from the speakers. regardless of slugcat’s location in the room. Clicking the sound again in the list will remove it. |- | Spot || Sounds placed with this option will have a radial tool to control where they are heard at their maximum volume, and how far their noise tapers out around them. Dragging the sound into the bottom left trash box will remove it. |} |-| Map= {{todo|target=tab}} [[File:mapTab.png|400px|right|border|]] While you will be able to edit and tweak the map ingame, the in game map will only be loaded again on a full restart of Rainworld. It will often be broken as well due to previous exploration of the map. To properly test your map, you will need a backup file from before you entered the region, or to reset the file entirely, and restart the game again. This tool is very picky, and often rendering/exporting the map will fail until you restart Rainworld. === General controls === NOTICE! Although general controls are behind the map (and are slightly darker due to this), they still function exactly the same! === Save: === Saves the current map properties. Layout, dev view, enemy preferences, and all. To the region’s properties text file, and map text file. NOTICE! It is important to ALWAYS save before you leave the map tab! The map will reset to its previous state if you change to another tab, or close dev tools! Changing between canon/dev modes will not reset the map. However saving often in this tab is a good habit. == Modes: == There are two specific map modes, canon, and dev. Canon mode is the maps appearance ingame, and dev mode allows you to set specific properties of rooms, such as creature’s attraction to it, and their sub region. === Dev View ==== [[File:mapConnections.png|400px|right|border|Connections on dev map]] This mode displays every room tied to the region, their names, and their doors. Lines are drawn between connected doors. Disconnected doors will show an unconnected diagonal line. Doors that do not have a proper connection in their destination room will point into the center of that room’s icon instead of to a door. Properly linked doors will show two lines. One going from each room to the proper door on the other end. The placement of these rooms will not change the map that the player sees in game, nor does it affect room settings that require specific map heights like “AboveCloudsView”, and can be aligned to your convenience. ==== Understanding Entrance Types: ==== There are various doors in and out of rooms. These not only include the doors slugcat can use to travel between rooms, but also creature dens, and unique doors; Such as the automatically added sky doors for vultures. The dev view outlines each door in every room connected to the region. Allowing you to easily see which rooms have specific doors as you edit the [https://rain-world-modding.fandom.com/wiki/World_File_Format World File]. The specific doors are as follows: * Gray Squares are for pipes that travel between adjacent maps. These should not be used for creature spawns. * Light Blue Squares are spawn locations in the sky for Vultures. * Dark Blue Squares are underwater spawn locations for Leviathans. * Dark Gray Squares are travel locations for Scavengers. * Brown Squares are spawn locations for Garbage Worms * Bright Green Squares are spawn locations for Batflies * Pale Green Squares are side entrances that can be used by Miros Birds * Magenta Squares are the standard creature spawn locations for all other types of creatures. ==== Reset Dev Positions: ==== Holding N and pressing this button will move all rooms to their canon locations. Not used often, Really only useful if you somehow have lost a room off screen. ==== Room Attractiveness Tool: ==== This tool allows you to select an enemy, or enemy class from the right hand menu, and specifically tweak what rooms they love, avoid, are neutral to, stay in, or are not allowed inside of while wandering the map. This does not apply to when an enemy is in pursuit of slugcat, or to tamed creatures. Who will follow you into rooms that are forbidden to them, but try to leave as soon as they return to their normal lurking mode. The menu on the right allows you to select a specific enemy, and then the tool’s mode at the bottom. Clicking a map screen while “cycling” will change it between the various attractiveness options. Clicking the TOOL button will change it to setting specific modes. Clicking “apply tool to all rooms” with a specific mode selected, will paint every room to that mode. Helpful if you want an enemy to only wandering one or two rooms of a huge map, but don’t want to set every other room to forbidden manually. ==== Sub Regions Tool: ==== This mode will allow you to click map screens, and to change them between the various sub regions inside the map region’s properties.txt file. The NONE sub region is a special flag that will not display an area name until you have entered another sub region. Save rooms and gates automatically have their sub region forcefully set to NONE, and cannot be changed. === Canon View === [[File:mapCanon.png|400px|right|border|Canon view of the map]] This mode is for constructing the map that the player will actually see in game. If you require the actual location of the room in X and Y you will need to open the map_XX.txt file in the region. As some unique effects require specific heights. More details can be found in the [[Room-Settings.html|Room Settings Tab]]. ==== Render Map: ==== This button will export the canon map as a texture, containing the three layers the map uses to draw the in game map. In some cases this will fail. Often due to using it multiple times, or tweaking the map too much. It is a very picky tool. Restarting the game will fix this, and allow you to export properly again. Be sure to save after you export the canon map, as failing to save before you leave the map tab will result in the map resetting to the last save. === Create Def. Mat. Rectangle === {{todo}} <span id="rendering-minimaps"></span> == Rendering Minimaps == [[File:mapRender.png|400px|right|border|Example of a rendered map .png file]] Minimaps can be constructed and rendered through the Map Tab. The map tab has four different editing modes: Canonical View, Subregion View, Attractiveness View, and Dev View. For minimap editing, you want to be in the Canon View. While in Dev view, click and drag a room to reposition it. Click and drag anywhere else to scroll the canvas around. While holding the N key, click a room to change what layer it is in. There are three layers, green being the closest, grey being the middle, and red being the furthest back. In general, you should avoid overlapping any rooms that are in the same layer as each other. Overlapping rooms that are in different layers is fine. You can click the Save button to save your changes. You should do this periodically to avoid losing any progress. When you are finished positioning all the maps how you want them, click the Render button to generate the final minimap. (This render step tends to fail a lot, see the troubleshooting section below for solutions) === Troubleshooting === When rendering the minimap, sometimes it will fail. It will either generate a completely empty map (the rendered map image will just be an empty green rectangle), or it will generate a map, but all the map interconnections will be undefined (when you view the minimap, the dotted lines that connect the rooms will either be missing, or will curve all over the place randomly). Here is the most reliable procedure I’ve found to have success in rendering the final map: * When you are done making your changes, hit the save button, but do not hit the render button. * Exit the game, and either start a new save file, or revert to a save file from before you entered the region for the first time. * Enter the region fresh, and as soon as you enter the region, go to dev mode, open the dev view map and render it. * The map should be correctly rendered now. |-| Triggers= {{todo|target=tab}} [[File:triggerTab.png|600px|right|border|Trigger tab view]] <span id="general-controls"></span> == General controls == === Save === Saves the current effects and room settings to a file inside the region’s World folder, named ROOMNAME_settings.txt Most effects are not applied instantly, and thus need to be saved, and then reloaded by pressing R and returning to the room to see the changes. === Inherent from template === Will set the values stored in a specific template the region has to this room. === Save as template: === Saves the current room’s settings as a template for easy re-use. == Triggers Menu == '''Triggers''' are the mechanism in which some in-game events occur, such as specific songs playing, projections being displayed by the player guide overseer, or information text being displayed at the bottom of the screen. Clicking one of the four options in the bottom right-hand box will place a trigger of that type, which can be moved just like other devtools objects. === Trigger Options === Triggers have a number of settings which determine what the trigger does and under what circumstances. {| class="wikitable" |+ |- ! Trigger setting !! Description |- | Active from cycle || The minimum total cycle requirement for the trigger to activate. |- | Active up to cycle || The maximum cycle limit for the trigger to activate - if the player has a cycle count higher than this number, the trigger will not activate. |- | Fire chance || A random percentage chance for the trigger to activate, from 0% to 100%. |- | Trigger delay || How many seconds between the requirements for the trigger being met and the event occurring. |- | Karma req || The minimum karma the player needs for the trigger to activate (from 0 to 5) |- | Can only fire once/Can fire multiple times || Self-explanatory, determines whether the trigger only fires once or not. |- | No entrance requirement/Entrance XX || Determines whether the player can enter from any entrance pipe, or whether they need to come through a specific one. When an entrance is selected, a red line will connect this entrance and the options box. |- | White, Yellow, Red || Determines which gamemodes the trigger fires on - Survivor, Hunter or Monk. A gamemode’s name being displayed means that the trigger will fire in said gamemode. |} === Event Types === The lowest button on the options box lets you pick what type of event you want to add. ==== MusicEvent ==== Plays a song from the soundtrack. * The first button lets you pick the song you want to play. Files for these songs can be found in *Rain World, or many of them can be found [https://www.youtube.com/playlist?list=PLPJWSVeszYFBo1oAXYgzGfJfewnGKgGna online.] {| class="wikitable" |+ MusicEvent options |- ! Option !! Description |- | Play volume || The volume the song plays at. |- | Fade in || In seconds, how long the song takes to reach full volume. |- | Song priority || If this song’s priority is higher than another’s, then this song will continue to play if the other trigger is activated. If the priority is lower, then the higher one will play instead of it. |- | Drone volume || WIP, presumably adds a background drone sound at the set volume. |- | Fade out at threat || The threat level at which the song fades out and is overtaken by the threat music. |- | Rest cycles || If this trigger can activate multiple times, the number of cycles for the trigger to wait before being able to fire again. |- | Room transitions || How many rooms the song will continue playing through. |- | One song per cycle || Whether or not the same song can activate multiple times in one cycle. |- | Play once/loop || Determines whether the song plays once or loops |- | Continue at death || Continue playing the song when the player dies. |- | Continue through gate || Continue playing the song when the player uses a region gate. |} ==== StopMusicEvent ==== As the name says, stops one or more MusicEvents. The first button lets you pick the song you want to stop/exclude. * '''Priority:''' If a song has a higher priority than the trigger, it won’t stop. * '''Fade out:''' Same as fade in, but fading out to silence. * '''Stop all songs/stop specific song/stop all but specific song:''' Self-explanatory, song selected at the top of the box is what this refers to. ==== '''PoleMimicSubtleReveal''' ==== Causes a pole mimic to flutter slightly when activated. ==== '''ShowProjectedImageEvent''' ==== Shows player guide overseer projections ==== '''RoomSpecificTextMessage''' ==== Causes specific text prompt to appear. Prompts are hardcoded by room name {{Cn}} ==== '''BringPlayerGuideToRoom''' ==== Forces player overseer to current room === Trigger Types === * '''Spot:''' The most commonly used trigger; activates when slugcat walks into a specific circular area of the room. This is indicated by a white area-of-effect which can be moved and scaled. * '''SeeCreature:''' ''WIP, presumably activates upon a certain creature being seen.'' * '''RegionBump:''' Activates either when the region is entered or at the beginning of a cycle where the region name and cycle count is shown. * '''PreRegionBump:''' Seemingly functions the same way as RegionBump. </tabber> </div> [[Category:Dev Tools]] cdc1a1b4cdccf7db947ac4a8a6731e2c094bd909 Category:Code Mods 14 74 566 463 2023-10-26T14:52:23Z Hrobo776 323 wikitext text/x-wiki Code mods are incredibly versatile. They allow for fixing bugs in the vanilla game, adding quality of life (QoL) features, and all sorts of brand new features including new creatures and gamemodes. Code mods are sometimes included in Region Packs, either as supplimentary features or dependencies of those features. To load code mods, we use a modified version of [[BepInEx]]. == Writing Code Mods == Rain World is programmed in C# with Unity, meaning that we have access to plenty of .NET and Unity oriented modding tools. RW code mods are generally written in C# and built for the .NET Framework 4.8 runtime. If you're looking to start making code mods, it's recommended that you start with [[BepInPlugins]]. You're likely to get the most support with these, they're the easiest to make, and they're very capable. Before diving into the details of writing a code mod, you'll need to [[Code Environments|set up your code environment]]. Also, knowing [[Rain World Code Structure]] helps a lot. Modern Rain World code mods typically come in a few flavours... * [[BepInPlugins]] - ''the most common. They largely use a technique called hooking, which allows for many possibilities and makes for good compatibility with other mods.'' * [https://docs.bepinex.dev/articles/dev_guide/preloader_patchers.html Preloader Patchers] - ''powered by Mono.Cecil. Used to apply changes to assemblies during the preloader phase.'' Older Rain World code mods are generally: * [[Standalone Mods]] * [[Partiality Mods]] * [[MonoMod Patches]] 8105371b0bb139e25f15bf9a9d212834c6edea47